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

  1. 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>`
  2. Replace the symbolic ref with a hard ref: `git update-ref <ref> $(git rev-parse <target>)`
  3. 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

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


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