fix(docker): stale bind-mount inode to Docker Desktop on up/delete/up#519
Conversation
Workspace `up` failed intermittently on Docker Desktop after an up -> delete -> up cycle: the daemon rejected the workspace bind mount with "bind source path does not exist: /host_mnt/..." even though the host path existed. Root cause is Docker Desktop's file-sharing layer caching a stale inode for the workspace's recreated parent directory. `workspace delete` does os.RemoveAll on .../workspaces/<id>, and the next `up` recreates the same .../agent/ path with a new host inode; the VM still maps the old one and cannot resolve children created under it. Retrying the same mount in place never succeeds. PR #512's content-<uid> leaf did not help because the poisoned directory is the parent agent/, which the lookup must traverse regardless of the leaf name. Fix: add bind-create-src=true to the workspace bind mount on runtimes that parse it (Docker only). This forces the daemon to re-resolve the source through the file share, busting the stale inode; because the directory really exists it binds the real content. The option is gated on an os.Stat existence check so a genuinely missing source still fails loudly (exit 125) instead of being silently created as an empty dir. Also drop the now-pointless content-<uid> suffix back to a plain "content" path, since it never delivered the protection it was added for and bind-create-src is the real fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
✅ Deploy Preview for devsydev canceled.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (10)
💤 Files with no reviewable changes (1)
📝 WalkthroughWalkthroughThe PR removes the UID suffix from the agent workspace content directory (replacing ChangesWorkspace content directory path simplification
Docker bind-cache busting
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Deploy Preview for images-devsy-sh canceled.
|
The bind-create-src mount option is only parsed by the docker CLI v29+,
and only relevant on Docker Desktop. Emitting it unconditionally broke
every `up` on Linux CI (docker 28.0.4), which rejects the unknown mount
key at parse time:
invalid argument ... unexpected key 'bind-create-src'
Gate it three ways instead of the previous runtime-name-only capability:
- Docker runtime (Podman/nerdctl reject the option)
- Docker Desktop only (GOOS != linux); native Linux binds the host
path directly and never hits the file-share inode cache
- docker CLI >= v29, detected via `docker version`; older clients
error out, which would turn the intermittent bug into a hard failure
Adds DockerHelper.ClientVersion and replaces SupportsBindCreateSrc() with
shouldBustBindCache()/dockerMajorAtLeast() in the driver.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The up -> delete -> up bind-mount failure on Docker Desktop is caused by the bind-mount source's PARENT directory being delete+recreated at the same host path. Docker Desktop's file share caches the parent inode; once it is recreated, the VM can no longer resolve bind sources beneath it. The content folder lived at workspaces/<id>/agent/content, entirely inside the workspaces/<id> tree that `delete` removes with RemoveAll, so every delete churned the parent inode. Move the host-side content folder to a per-context contents/<id> dir. The contents/ parent is created once and never removed on delete (only the <id> leaf is), so its host inode stays stable across recreate and the file share keeps resolving the bind source. Verified: up/delete/up cycles pass 5/5 with bind-create-src disabled (i.e. this fixes Docker Desktop versions older than v29 that lack the flag), and inode tracking confirms contents/ is never recreated while the leaf is. bind-create-src is retained as a fast path / extra safety on v29+. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Condense the explanatory comments added for the bind-mount fix to concise doc comments and one-liners. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split the content-folder cleanup if-init statement so the line stays under the 100-char golines limit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Problem
Workspace
upfails intermittently on Docker Desktop after an up → delete → up cycle. The daemon rejects the workspace bind mount with:...even though
os.Lstatconfirms the host path exists. Symptom: the workspace cannot be brought up twice consecutively (up → delete → up again fails).Root cause
Docker Desktop's file-sharing layer (VirtioFS/gRPC-FUSE) caches a stale inode for the workspace's recreated parent directory.
workspace deleterunsos.RemoveAll(.../workspaces/<id>).uprecreates the same.../agent/path with a new host inode.This was reproduced deterministically:
content-<uid>)bind-create-src=trueacross recreated-parent cyclesPR #512's
content-<uid>leaf didn't help because the poisoned directory is the parentagent/, which the lookup must traverse regardless of the leaf name.Fix
Add
bind-create-src=trueto the workspace bind mount on runtimes that parse it (Docker only; Podman/nerdctl reject unknown mount options). This forces the daemon to re-resolve the source through the file share — busting the stale inode — and because the directory really exists, it binds the real content, not an empty placeholder.The option is gated on an
os.Statexistence check: a genuinely missing source is left untouched so docker still fails loudly (exit 125bind source path does not exist) instead ofbind-create-srcsilently materializing an empty directory and starting the container against an empty workspace.Also drops the now-pointless
content-<uid>suffix back to a plaincontentpath — it never delivered the protection it was added for, andbind-create-srcis the real fix.Summary by CodeRabbit
New Features
Bug Fixes
Refactor