gastownhall/beads · error

failed to resolve path: %w

Error message

failed to resolve path: %w

What it means

After joining and re-relativizing, safeWorkspacePath could not compute filepath.Rel(absRoot, joined). In practice this is nearly unreachable: since joined is built from absRoot via Join, Rel always succeeds on the same platform. It is a defensive wrap of the Rel error (can occur on cross-volume path computation on some platforms).

Source

Thrown at cmd/bd/doctor/fix/common.go:117

}

// safeWorkspacePath resolves relPath within the workspace root and ensures it
// cannot escape the workspace via path traversal.
func safeWorkspacePath(root, relPath string) (string, error) {
	absRoot, err := filepath.Abs(root)
	if err != nil {
		return "", fmt.Errorf("invalid workspace path: %w", err)
	}

	cleanRel := filepath.Clean(relPath)
	if filepath.IsAbs(cleanRel) {
		return "", fmt.Errorf("expected relative path, got absolute: %s", relPath)
	}

	joined := filepath.Join(absRoot, cleanRel)
	rel, err := filepath.Rel(absRoot, joined)
	if err != nil {
		return "", fmt.Errorf("failed to resolve path: %w", err)
	}

	if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
		return "", fmt.Errorf("path escapes workspace: %s", relPath)
	}

	return joined, nil
}

// isWithinWorkspace reports whether candidate resides within the workspace root.
func isWithinWorkspace(root, candidate string) bool {
	cleanRoot, err := filepath.Abs(root)
	if err != nil {
		return false
	}
	cleanCandidate := filepath.Clean(candidate)
	rel, err := filepath.Rel(cleanRoot, cleanCandidate)
	if err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry after confirming root and relPath are plain native-platform paths (no mixed separators or volume prefixes)
  2. Report as a bug if reproducible: joined is constructed from absRoot, so Rel should never fail
  3. Ensure the code is not modified to bypass the Join step with externally supplied joined paths
  4. Update Go toolchain if a stdlib path bug is suspected
Defensive patterns

Strategy: try-catch

Validate before calling

if filepath.IsAbs(root) && filepath.Clean(rel) != rel {
    rel = filepath.Clean(rel)
}

Try / catch

p, err := safeWorkspacePath(root, rel)
if err != nil {
    if strings.HasPrefix(err.Error(), "failed to resolve path") {
        // defensive branch; report as a bug with the inputs
    }
    return err
}

Prevention

When it happens

Trigger: filepath.Rel(absRoot, joined) returning an error — theoretically possible only with mismatched path forms across volumes; the joined value here is derived from absRoot, so this is a defensive branch.

Common situations: Rare; encountered only if the Go runtime/platform behaves unexpectedly or code is modified to pass arbitrary pre-joined paths.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/c585d004b66b5ab9. Report an issue: GitHub.