Chatbot conversation

Fixing macOS Ghost Mount Points: How I Stopped “external 1” From Appearing

Fixing macOS Ghost Mount Points: How I Stopped “external 1” From Appearing

Date: November 16, 2025

Context

I’m enforcing an external-only home directory on macOS. Sometimes, if the external disk isn’t present, macOS quietly creates a local folder at /Volumes/external to keep the session alive. Later, when I plug in the actual drive, the system avoids the collision by mounting it as external 1. That silent behavior breaks my setup and creates confusion.

Symptoms

  • Mount collision: Real disk mounts as /Volumes/external 1 instead of /Volumes/external.
  • Ghost folder: A plain directory exists at /Volumes/external without a device backing it.
  • Recovery view: In Recovery Mode, internal volumes appear under /Volumes/Macintosh HD/Volumes/.

What worked: Remove the ghost folder

The fix was simple and surgical: delete the ghost directory so the real external can claim its rightful mount point. In Recovery Mode, the ghost may live under the internal volume path:

# In Recovery Mode:

ls -la "/Volumes/Macintosh HD/Volumes"

# If you see a plain directory named 'external', remove it:

sudo rm -rf "/Volumes/Macintosh HD/Volumes/external"

    

After removing the ghost, the external mounted cleanly at /Volumes/external again.

How to verify real vs ghost

  • List contents: ls -la /Volumes/external — real drives show full file trees; ghosts are sparse or empty.
  • Device check: diskutil info /Volumes/external — real drives report identifiers like /dev/disk2s1; ghosts don’t.
  • Dual names: If both external and external 1 exist, one is the ghost, the other is the mounted drive. Confirm before deleting.

Using immutable flags correctly

The immutable flag (uchg) protects the mount point from being modified or recreated when the disk is missing. But timing matters. If you lock the path while the disk is mounted, you may make the live filesystem feel read-only.

Sequence to enforce mount point without blocking usage:
# 1) Unmount the external if currently mounted

diskutil unmount /Volumes/external

# 2) Create (or ensure) the empty mount point, then lock it

sudo mkdir -p /Volumes/external

sudo chflags uchg /Volumes/external

# 3) Reconnect or mount the external; it will mount over the locked directory

diskutil mount /dev/diskXsY  # replace with your actual slice

# If you ever need to undo:

sudo chflags nouchg /Volumes/external

      

Locked empty mount point = no ghost creation. Once the disk is mounted, normal read/write behavior resumes. If you set uchg while the disk was mounted and it feels locked, clear it with sudo chflags nouchg /Volumes/external, unmount, then apply uchg to the empty directory only.

Recovery Mode walkthrough

# 1) Boot into Recovery (⌘+R) and open Terminal

# 2) Identify disks

diskutil list

# 3) Mount the external manually (adjust diskXsY)

diskutil mount /dev/diskXsY

# 4) Inspect volumes

ls /Volumes

ls "/Volumes/Macintosh HD/Volumes"

# 5) Remove ghost directories found under the internal:

sudo rm -rf "/Volumes/Macintosh HD/Volumes/external"

# 6) Confirm the external mounts as /Volumes/external

ls -la /Volumes/external

diskutil info /Volumes/external

    

Optional automation

To keep the system clean at boot/wake, a small launchd job can scan /Volumes for known ghost names, verify with diskutil info, and remove empty stubs before login. Pair this with the immutable mount point for belt-and-suspenders protection.

Key takeaways

  • Ghosts cause “external 1”: If a plain folder exists at /Volumes/external, the real disk will be renamed on mount.
  • Delete the ghost in Recovery: Especially if it lives under /Volumes/Macintosh HD/Volumes/.
  • Lock the empty mount point: Use chflags uchg on the directory when the disk is not mounted.
  • Verify before deleting: diskutil info distinguishes real volumes from plain directories.
  • Eject cleanly: Always eject before unplugging to avoid stale folders.
If you want a ready-to-run launchd job to auto-clean ghost folders at boot, I can share a minimal plist and script. It’s a set‑and‑forget guardrail for mount hygiene.

Comments

Popular posts from this blog

What “create .env.local (do not commit)” really means

Chatbot session