Skip to content

fix bind-mount failure on macOS Docker Desktop#2021

Open
ericcurtin wants to merge 1 commit into89luca89:mainfrom
ericcurtin:macOS-dd-fix
Open

fix bind-mount failure on macOS Docker Desktop#2021
ericcurtin wants to merge 1 commit into89luca89:mainfrom
ericcurtin:macOS-dd-fix

Conversation

@ericcurtin
Copy link
Copy Markdown
Contributor

Docker Desktop on macOS only shares specific directories with its Linux VM via VirtioFS ($HOME, /private, /Volumes, /tmp). Scripts installed to /usr/local/bin (e.g. via Homebrew) are not accessible, so Docker creates an empty directory placeholder in the VM. This makes /usr/bin/entrypoint a directory in the container, causing runc to fail with "is a directory".

distrobox-create: on Darwin, copy distrobox-init, distrobox-export, and distrobox-host-exec to ~/.local/share/distrobox/ (always under $HOME, always VirtioFS-shared) before using them as bind-mount sources.

distrobox-enter: the self-healing detection code reads .HostConfig.Binds, which Docker Desktop returns with a /host_mnt prefix (the VM's view of the VirtioFS mount). Strip this prefix on Darwin before checking file existence, preventing a spurious "mkdir: /host_mnt: Read-only file system" crash even for correctly-created containers.

@ericcurtin
Copy link
Copy Markdown
Contributor Author

I didn't notice this before because during development was using my git repo which is in $HOME

@ericcurtin ericcurtin force-pushed the macOS-dd-fix branch 6 times, most recently from 65f34c7 to fdeabc9 Compare March 19, 2026 14:59
@89luca89
Copy link
Copy Markdown
Owner

89luca89 commented Mar 19, 2026

Would it make sense to have this logic as a pre-flight check in distrobox command instead? So it's all in one place?
It would defy it when people use distrobox-create or distrobox-enter directly but this should be rare enough (given that single entrypoint is suggested as default from the beginning almost)

EDIT: or maybe we can fix it on brew tap to contextually install it to ~/.local/bin too (or only there)
EDIT2: also I'm worried about stale entries during upgrades, or uninstalls

@ericcurtin
Copy link
Copy Markdown
Contributor Author

What about a hard link? Then we never go stale, because the same file is shared

@89luca89
Copy link
Copy Markdown
Owner

What about a hard link? Then we never go stale, because the same file is shared

If it works on macos like it works on linux I suppose yes, cp should preserve inode number.
But what about on uninstall? We can handle the uninstall via script, but brew won't cover it, and copied scripts will be kept around, and based on the user's setup, it might still be accessible (if they have ~/.local/bin in PATH)

@ericcurtin
Copy link
Copy Markdown
Contributor Author

Regarding the hard link idea: it might be risky because Homebrew updates often replace the file (creating a new inode), which would leave the hard link pointing to a stale/orphaned version of the script.

What if we treat ~/.local/share/distrobox/ as a managed cache?

  1. In the main distrobox entry point, we add a macOS-specific check.
  2. If the scripts in /usr/local/bin are newer than the ones in ~/.local/share, we cp them over.
  3. This solves the 'stale entry' problem on upgrades automatically.

For uninstalls, it does leave a small footprint, but that's fairly standard for macOS CLI tools. We could just document it or add a cleanup flag to distrobox-rm. This keeps the logic centralized and avoids the VirtioFS mount issues entirely.

@89luca89
Copy link
Copy Markdown
Owner

Regarding the hard link idea: it might be risky because Homebrew updates often replace the file (creating a new inode), which would leave the hard link pointing to a stale/orphaned version of the script.

What if we treat ~/.local/share/distrobox/ as a managed cache?

  1. In the main distrobox entry point, we add a macOS-specific check.
  2. If the scripts in /usr/local/bin are newer than the ones in ~/.local/share, we cp them over.
  3. This solves the 'stale entry' problem on upgrades automatically.

For uninstalls, it does leave a small footprint, but that's fairly standard for macOS CLI tools. We could just document it or add a cleanup flag to distrobox-rm. This keeps the logic centralized and avoids the VirtioFS mount issues entirely.

Agree, it should be in one entry point and should handle staleness
For the litter, well yea we should document that, maybe brew folks also have a solution, I don't know

Docker Desktop on macOS only shares specific directories with its Linux VM
via VirtioFS ($HOME, /private, /Volumes, /tmp). Scripts installed to
/usr/local/bin (e.g. via Homebrew) are not accessible, so Docker creates
an empty directory placeholder in the VM. This makes /usr/bin/entrypoint
a directory in the container, causing runc to fail with "is a directory".

distrobox-create: on Darwin, copy distrobox-init, distrobox-export, and
distrobox-host-exec to ~/.local/share/distrobox/ (always under $HOME,
always VirtioFS-shared) before using them as bind-mount sources.

distrobox-enter: the self-healing detection code reads .HostConfig.Binds,
which Docker Desktop returns with a /host_mnt prefix (the VM's view of the
VirtioFS mount). Strip this prefix on Darwin before checking file existence,
preventing a spurious "mkdir: /host_mnt: Read-only file system" crash even
for correctly-created containers.

Signed-off-by: Eric Curtin <eric.curtin@docker.com>
@ericcurtin
Copy link
Copy Markdown
Contributor Author

@89luca89 made another change, let me know what you think

@ericcurtin
Copy link
Copy Markdown
Contributor Author

My biggest worry about only putting the scripts in ~/.local/ in thing's like this won't "just work"

curl -s https://raw.githubusercontent.com/89luca89/distrobox/main/install | sudo sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants