{"record":{"id":"67228ebf5c26d16a","repo":"gastownhall/beads","slug":"symbolic-ref-q-resolves-outside-refs-q","errorCode":null,"errorMessage":"symbolic ref %q resolves outside refs/: %q","messagePattern":"symbolic ref %q resolves outside refs/: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/worktree_cmd.go","lineNumber":1917,"sourceCode":"func resolveWorktreeTerminalRef(\n\tctx context.Context,\n\tgit *worktreeRemovalGit,\n\texecutionRoot string,\n\tref string,\n) (string, error) {\n\tcurrent := ref\n\tseen := make(map[string]struct{})\n\tfor range 16 {\n\t\tif _, duplicate := seen[current]; duplicate {\n\t\t\treturn \"\", fmt.Errorf(\"symbolic ref cycle while resolving %q\", ref)\n\t\t}\n\t\tseen[current] = struct{}{}\n\n\t\toutput, err := git.output(ctx, executionRoot, \"symbolic-ref\", \"--quiet\", current)\n\t\tif err == nil {\n\t\t\tnext := strings.TrimSpace(string(output))\n\t\t\tif !strings.HasPrefix(next, \"refs/\") {\n\t\t\t\treturn \"\", fmt.Errorf(\"symbolic ref %q resolves outside refs/: %q\", current, next)\n\t\t\t}\n\t\t\tcurrent = next\n\t\t\tcontinue\n\t\t}\n\t\tvar exitError *exec.ExitError\n\t\tif errors.As(err, &exitError) && exitError.ExitCode() == 1 {\n\t\t\treturn current, nil\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"failed to inspect symbolic ref %q: %w\", current, err)\n\t}\n\treturn \"\", fmt.Errorf(\"symbolic ref chain for %q exceeds 16 links\", ref)\n}\n\nfunc resolveWorktreeCommitOID(\n\tctx context.Context,\n\tgit *worktreeRemovalGit,\n\texecutionRoot string,\n\trefOrOID string,","sourceCodeStart":1899,"sourceCodeEnd":1935,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/worktree_cmd.go#L1899-L1935","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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"],"exampleFix":"// before: symbolic ref points outside refs/\n$ git symbolic-ref refs/heads/bad HEAD\n// after: point it into refs/\n$ git symbolic-ref refs/heads/bad refs/heads/main","handlingStrategy":"validation","validationCode":"// ensure every symbolic ref in the chain stays inside refs/\nout, _ := exec.Command(\"git\", \"symbolic-ref\", \"--quiet\", ref).Output()\nif target := strings.TrimSpace(string(out)); target != \"\" && !strings.HasPrefix(target, \"refs/\") {\n\treturn fmt.Errorf(\"ref %q points outside refs/: %q\", ref, target)\n}","typeGuard":"func isNamespacedRef(ref string) bool {\n\treturn strings.HasPrefix(ref, \"refs/\")\n}","tryCatchPattern":"_, err := bd.WorktreeRemove(name)\nif err != nil && strings.Contains(err.Error(), \"resolves outside refs/\") {\n\t// repoint the offending ref, then retry\n\treturn repairAndRetry(name)\n}","preventionTips":["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"],"tags":["git","symbolic-ref","refs-namespace","worktree"],"backgroundTag":"git-symbolic-ref-outside-refs","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}