gastownhall/beads · error
symbolic ref %q resolves outside refs/: %q
Error message
symbolic ref %q resolves outside refs/: %q
What it means
While following a symbolic ref chain, bd requires every intermediate resolution to stay inside the `refs/` namespace, since only refs can be chained this way for containment proofs. This error is thrown when `git symbolic-ref` returns a target outside `refs/` (such as `HEAD` detached output or a pseudo-ref like `ORIG_HEAD`). Such a chain cannot be used to prove worktree containment, so bd aborts.
Source
Thrown at cmd/bd/worktree_cmd.go:1917
func resolveWorktreeTerminalRef(
ctx context.Context,
git *worktreeRemovalGit,
executionRoot string,
ref string,
) (string, error) {
current := ref
seen := make(map[string]struct{})
for range 16 {
if _, duplicate := seen[current]; duplicate {
return "", fmt.Errorf("symbolic ref cycle while resolving %q", ref)
}
seen[current] = struct{}{}
output, err := git.output(ctx, executionRoot, "symbolic-ref", "--quiet", current)
if err == nil {
next := strings.TrimSpace(string(output))
if !strings.HasPrefix(next, "refs/") {
return "", fmt.Errorf("symbolic ref %q resolves outside refs/: %q", current, next)
}
current = next
continue
}
var exitError *exec.ExitError
if errors.As(err, &exitError) && exitError.ExitCode() == 1 {
return current, nil
}
return "", fmt.Errorf("failed to inspect symbolic ref %q: %w", current, err)
}
return "", fmt.Errorf("symbolic ref chain for %q exceeds 16 links", ref)
}
func resolveWorktreeCommitOID(
ctx context.Context,
git *worktreeRemovalGit,
executionRoot string,
refOrOID string,View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the chain: `git symbolic-ref <ref>` and repoint the offending ref at a real branch under refs/heads/ with `git symbolic-ref <ref> refs/heads/<branch>`
- Replace the symbolic ref with a hard ref: `git update-ref <ref> $(git rev-parse <target>)`
- Avoid chaining through HEAD; pass a concrete branch as the `--merged-into <ref>` comparator instead
Example fix
// before: symbolic ref points outside refs/ $ git symbolic-ref refs/heads/bad HEAD // after: point it into refs/ $ git symbolic-ref refs/heads/bad refs/heads/main
Defensive patterns
Strategy: validation
Validate before calling
// ensure every symbolic ref in the chain stays inside refs/
out, _ := exec.Command("git", "symbolic-ref", "--quiet", ref).Output()
if target := strings.TrimSpace(string(out)); target != "" && !strings.HasPrefix(target, "refs/") {
return fmt.Errorf("ref %q points outside refs/: %q", ref, target)
} Type guard
func isNamespacedRef(ref string) bool {
return strings.HasPrefix(ref, "refs/")
} Try / catch
_, err := bd.WorktreeRemove(name)
if err != nil && strings.Contains(err.Error(), "resolves outside refs/") {
// repoint the offending ref, then retry
return repairAndRetry(name)
} Prevention
- Point symbolic refs only at branches under refs/heads/, never at HEAD or ORIG_HEAD
- Audit custom refs with `git for-each-ref --format='%(refname) %(symref)'`
- Use `--merged-into <branch>` with a plain branch name as the comparator
When it happens
Trigger: A symbolic ref in the chain points to a non-`refs/` target, e.g. a ref whose symbolic target is `HEAD`, `ORIG_HEAD`, `FETCH_HEAD`, or any pseudo-ref; triggered from `pinWorktreeComparatorRef` -> `resolveWorktreeTerminalRef`.
Common situations: Someone created a symbolic ref pointing directly at HEAD instead of a branch; unusual Git configurations or hooks that create pseudo-ref symbolic targets; refs migrated between repositories with inconsistent ref layouts.
Related errors
- symbolic ref cycle while resolving %q
- failed to inspect symbolic ref %q: %w
- symbolic ref chain for %q exceeds 16 links
- failed to inspect created worktree cleanliness: %w %s
- created worktree is dirty after checkout; refusing to contin
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/67228ebf5c26d16a.
Report an issue: GitHub.