gastownhall/beads · error
workspacegate: resolving %s: %w
Error message
workspacegate: resolving %s: %w
What it means
workspacegate.forDir fails to resolve the given directory to an absolute path, wrapping the underlying filepath.Abs error as "workspacegate: resolving %s: %w". This happens before the gate file identity is computed, so no lock was taken. It is an infrastructure-level resolution failure, not a gate-conflict error.
Source
Thrown at internal/workspacegate/gate.go:165
// gateFileName maps a guarded directory base name to its sibling gate
// file name: ".beads" -> ".beads.gate.lock", "dolt" -> "dolt.gate.lock".
// The base is kept verbatim (no dot-stripping) so distinct sibling names
// can never collide on one gate file.
func gateFileName(base string) string {
return base + ".gate.lock"
}
// forDir builds the gate for a guarded directory: the gate file sits in
// the directory's parent. The parent must exist; the guarded directory
// itself may not exist yet (bd init gates the workspace it is creating).
// The parent is canonicalized (symlinks resolved) so that every process
// that reaches the same physical parent agrees on one gate file, no
// matter which path spelling it used.
func forDir(dir string) (Gate, error) {
abs, err := filepath.Abs(dir)
if err != nil {
return Gate{}, fmt.Errorf("workspacegate: resolving %s: %w", dir, err)
}
abs = filepath.Clean(abs)
// Gate identity must be stable across the guarded directory being
// absent, created, replaced, or recreated — that is the point of
// placing the gate beside it. So identity derives from the
// canonicalized PARENT plus the literal base name, never from
// resolving the guarded path itself: full-path resolution would
// silently select a different gate once the directory appears as a
// symlink, letting two exclusive holders coexist. The flip side is
// that a guarded directory that IS a symlink has no stable identity
// under this scheme, so it is refused outright rather than gated
// ambiguously.
if fi, err := os.Lstat(abs); err == nil && fi.Mode()&os.ModeSymlink != 0 {
return Gate{}, fmt.Errorf("workspacegate: %s is a symlink; gate the physical directory it points to", abs)
}
parent, base := filepath.Split(abs)
switch base {View on GitHub (pinned to 71377f2769)
Solutions
- Re-run the command from an existing directory (cd to a valid path first)
- Pass an absolute path to ForWorkspace/ForPhysicalRoot so filepath.Abs does not need the cwd
- Inspect the wrapped error (%w) for the OS-specific cause (e.g. ENOENT, ENAMETOOLONG) and fix the path accordingly
Example fix
// before
g, err := workspacegate.ForWorkspace(relDir)
// after
abs, err := filepath.Abs(relDir)
if err != nil { return fmt.Errorf("bad workdir %q: %w", relDir, err) }
g, err := workspacegate.ForWorkspace(abs) Defensive patterns
Strategy: try-catch
Validate before calling
if abs, err := filepath.Abs(dir); err != nil { return fmt.Errorf("cannot resolve %q: %w", dir, err) } Try / catch
g, err := workspacegate.ForWorkspace(dir)
if err != nil && strings.HasPrefix(err.Error(), "workspacegate: resolving ") { /* cwd/path issue: cd to a valid dir or use absolute path */ } Prevention
- Pass absolute, existing directories to gate entry points
- Check that the process cwd exists before relative-path calls (containers often have deleted cwds)
- Surface the wrapped %w error to diagnose OS-level causes like ENOENT or ENAMETOOLONG
When it happens
Trigger: Calling ForWorkspace(dir) or ForPhysicalRoot(dir) with a path that cannot be made absolute — practically this occurs when the current working directory is unavailable (e.g. the directory was deleted) and dir is relative, or on OS-level path resolution failures.
Common situations: Running bd from a directory that was removed or renamed by another process; containers or shells with a deleted cwd; extremely long or invalid path components on some filesystems.
Related errors
- invalid path: %w
- failed to read JSONL file %s: %w
- resolve path: %w
- uow: resolving server root dir: %w
- uow: resolving dolt bin exec: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/66ff816508506c4e.
Report an issue: GitHub.