[BUG] Launcher branch chip shows ".invalid" for repos using git's reftable backend (reads .git/HEAD directly)

Open 💬 1 comment Opened Jun 2, 2026 by rohandhruva

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

In a repository using git's reftable ref backend (extensions.refStorage = reftable), the launcher's current-branch chip shows .invalid instead of the actual branch (e.g. main). It persists across sessions and cache clears.

What Should Happen?

It should instead use:

  • git symbolic-ref --short HEAD (empty when detached → fall back to git rev-parse --short HEAD), or
  • parse the # branch.head line of git status --porcelain=v2 --branch.

Error Messages/Logs

Steps to Reproduce

Verified from scratch (git 2.54.0):

# 1. Create a repo on the reftable backend (or convert an existing one with:
#    git refs migrate --ref-format=reftable)
git init --ref-format=reftable /tmp/reftable-repro
cd /tmp/reftable-repro
git commit --allow-empty -m init      # creates the default branch (main)

# 2. Confirm reftable + that .git/HEAD is the vestigial stub while git is correct
git config extensions.refStorage      # -> reftable
cat .git/HEAD                         # -> ref: refs/heads/.invalid   (the stub)
git symbolic-ref --short HEAD         # -> main   (git resolves correctly)
git branch --show-current             # -> main
  1. Open this repo in the Claude launcher (the desktop/Cowork launcher branch chip).
  2. Observe: the branch chip shows .invalid instead of main.

Expected: branch chip shows main (matching git symbolic-ref --short HEAD).
Actual: shows .invalid (the raw .git/HEAD stub).

Claude Model

None

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.1.159

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Evidence

No error is thrown — this is a silent incorrect value, so it does not appear in crash/error logs.

Verified contradiction between the raw file and git on the same repo:

| source | value |
|---|---|
| raw .git/HEAD file read | ref: refs/heads/.invalid ❌ |
| git symbolic-ref --short HEAD | main ✅ |
| git rev-parse --abbrev-ref HEAD | main ✅ |
| git branch --show-current | main ✅ |
| git status --porcelain=v2 --branch# branch.head | main ✅ |

The launcher's own status block shows the bug directly — the current-branch line is read from the file while the "main branch" line is derived via git, so they disagree:

Current branch: .invalid
Main branch (you will usually use this for PRs): main
Status: (clean)

(Linked worktrees have the same stub at .git/worktrees/<wt>/HEAD.)

Root cause

The launcher resolves the current branch by reading the .git/HEAD file directly. Under reftable the real refs live in .git/reftable/, and .git/HEAD is a deliberate vestigial stub that git itself ignores — its contents are literally ref: refs/heads/.invalid. Any consumer that parses .git/HEAD as a file gets .invalid.

Suggested fix

Resolve the branch through git instead of reading the file:

  • git symbolic-ref --short HEAD (empty when detached -> fall back to git rev-parse --short HEAD), or
  • parse the # branch.head line of git status --porcelain=v2 --branch.

The same status block's "Main branch" line is already derived correctly via git — only the current-branch line reads the file, so this is a one-spot fix.

Notes

  • Likely a duplicate of #57454 (closed as duplicate; that report bundled this with a separate PR-ancestry-walker bug). Filing focused on just the reftable .git/HEAD read, since it's a clean self-contained fix.
  • Local stopgap (not a real fix, and git re-stamps it on the next checkout): printf 'ref: refs/heads/main\n' > .git/HEAD.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗