gastownhall/beads · error
ensureProxiedServerConfig: write %s: %w
Error message
ensureProxiedServerConfig: write %s: %w
What it means
The final step of ensureProxiedServerConfig writes the rendered YAML atomically via atomicWriteFile(resolveConfigWriteTarget(path), body); any write failure is wrapped here. resolveConfigWriteTarget resolves the path to its physical location first because os.Rename's destination does not follow symlinks — so this error covers temp-file creation, write, fsync, or rename failures at the real destination.
Source
Thrown at cmd/bd/proxied_server.go:158
switch _, err := os.Stat(path); {
case err == nil:
return path, nil
case !os.IsNotExist(err):
return "", fmt.Errorf("ensureProxiedServerConfig: stat %s: %w", path, err)
}
port, err := proxy.PickFreePort()
if err != nil {
return "", fmt.Errorf("ensureProxiedServerConfig: pick free port: %w", err)
}
body, err := renderProxiedServerConfig(port)
if err != nil {
return "", fmt.Errorf("ensureProxiedServerConfig: render YAML: %w", err)
}
if err := atomicWriteFile(resolveConfigWriteTarget(path), body); err != nil {
return "", fmt.Errorf("ensureProxiedServerConfig: write %s: %w", path, err)
}
return path, nil
}
// resolveConfigWriteTarget resolves path to its physical location before
// an atomic rewrite. os.Rename's destination argument does not follow
// symlinks — it unlinks and replaces whatever is AT that path, symlink or
// not — so writing straight to a symlinked config.yaml would silently
// replace the symlink itself with a regular file instead of updating the
// file it points at. Falls back to path unresolved when it does not exist
// yet (filepath.EvalSymlinks errors on a missing path), which covers both
// the ordinary "no config.yaml yet" case and a dangling symlink.
func resolveConfigWriteTarget(path string) string {
resolved, err := filepath.EvalSymlinks(path)
if err != nil {
return path
}
return resolvedView on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped errno: ENOSPC/quota → free space (`df -h <dir>`, `du -sh ~/.beads`) or raise the quota; EACCES → fix ownership of the config directory (`ls -ld ~/.beads`, `sudo chown -R $USER ~/.beads` if root-owned).
- If the filesystem is read-only (container overlay, immutable mount), remount rw or relocate the config to a writable path via a custom --config.
- Disable/repair interference from sync daemons: pause Dropbox/backup agents or move ~/.beads off the synced/network mount.
- Check LSM denials (SELinux audit log / AppArmor) and adjust policy if writes to the path are being blocked.
- Rerun the command after fixing conditions — the atomic write either succeeds fully or leaves the old file intact, so retry is safe.
Example fix
// before $ ls -ld ~/.beads drwx------ root root ~/.beads # root-owned after sudo run // after $ sudo chown -R $USER:$USER ~/.beads && bd serve
Defensive patterns
Strategy: try-catch
Validate before calling
dir := filepath.Dir(cfgPath)
if err := unix.Access(dir, unix.W_OK); err != nil {
return fmt.Errorf("cannot write config dir %s: %w", dir, err)
} Try / catch
if err := atomicWriteFile(target, body); err != nil {
switch {
case errors.Is(err, fs.ErrPermission):
// chown/chmod the beads dir or relocate config
case errors.Is(err, syscall.ENOSPC):
// free disk space / raise quota, then retry
default:
log.Printf("config write failed: %v", err)
}
return err
} Prevention
- Never run bd under sudo in ways that leave ~/.beads root-owned; chown it back if it happens.
- Keep the beads directory off read-only mounts and out of overlay filesystems in containers — mount a writable volume for it.
- Monitor disk space/quota on the volume hosting ~/.beads.
- Pause file-sync daemons (Dropbox, backup agents) for directories bd writes to atomically.
When it happens
Trigger: atomicWriteFile fails: parent dir not writable (EACCES), disk full (ENOSPC), target is inside a read-only mount or container layer, temp-file create/rename blocked by sandbox policy, or quota exceeded on the volume holding ~/.beads.
Common situations: Read-only container root filesystem with HOME on the overlay; full disk or user quota on $HOME; ~/.beads owned by root after a sudo run; SELinux/AppArmor denying writes; sync tools (Dropbox/NFS) holding locks or failing the rename.
Related errors
- failed to create temp file: %w
- ensureProxiedServerConfig: mkdir %s: %w
- ensureProxiedServerConfig: stat %s: %w
- identity: write proxy secret: %w
- dolt path is not executable
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/30c1391f484ae93a.
Report an issue: GitHub.