Codex App: "Create permanent worktree" always fails with `fatal: invalid reference: refs/heads/HEAD` when the project's checked-out branch has an upstream
What version of Codex is running?
Codex App for Windows (MSIX) 26.818.5229.0 — also reproduced on 26.818.3698.0 right before the auto-update. The bug is in the app bundle (app.asar), not in the codex core binary.
Which model were you using?
N/A — the failure happens in the worktree-creation dialog before any conversation starts.
What platform is your computer?
Windows 11 Pro 10.0.22631, git version 2.53.0.windows.2.
What steps can reproduce the bug?
- Open any git repository as a project in the Codex App where the checked-out branch has an upstream. A plain
git clonequalifies:maintracksorigin/main. - Sidebar → project
…menu → Create permanent worktree → type a name → Create.
Dialog log:
[info] Starting worktree creation
fatal: invalid reference: refs/heads/HEAD
[stderr] git worktree add failed: fatal: invalid reference: refs/heads/HEAD
The same repository works with a manual git worktree add, with the App's normal per-thread (temporary) worktrees, and with other tools' worktree features — only this dialog fails.
What is the expected behavior?
A new worktree checked out at the project's current HEAD, as the dialog promises ("Create a new git worktree from HEAD, add it as a project, and keep it until you remove it").
What do you see instead?
"Worktree setup failed" at the "Preparing workspace" step, with the log above.
Root cause (read from app.asar, 26.818.5229.0)
The "Create permanent worktree" dialog (i18n id sidebarElectron.createStableWorktree.*) submits the pending worktree with a hard-coded starting state:
startingState: { type: `branch`, branchName: `HEAD` } // launchMode: `create-stable-worktree`
The starting-ref resolver then treats the literal "HEAD" as a branch name:
- wraps it →
refs/heads/HEAD - looks up its upstream →
git rev-parse --abbrev-ref --symbolic-full-name HEAD@{u}— this succeeds whenever the checked-out branch has an upstream (returns e.g.origin/main) - compares →
git rev-list --left-right --count refs/heads/HEAD...refs/remotes/origin/main→ exit 128 (refs/heads/HEADis not a revision) → treated asnull - since the state is not
right-ahead, falls back to{ ref: "refs/heads/HEAD" } - runs
git worktree add --detach <path> refs/heads/HEAD→fatal: invalid reference: refs/heads/HEAD
Minified excerpt (26.818.5229.0):
function o6(e){return e.startsWith(`refs/`)?e:`refs/heads/${e}`}
async function c6(e,t,n){ // t === "HEAD"
let r=d6(t), // "refs/heads/HEAD"
i=await a6(e,t,n); // rev-parse --abbrev-ref --symbolic-full-name `${t}@{u}`
if(i!=null){
let a=`refs/remotes/${i}`,
o=await i6(e,`${a}^{commit}`,n)==null?o6(i):a;
return(await e6(e,r??t,o,n))?.state===`right-ahead` // rev-list --left-right --count refs/heads/HEAD...origin/main → fails → null
?{ref:o}
:{ref:r??t} // → {ref:"refs/heads/HEAD"}
}
...
}
// later: $(e,[`worktree`,`add`,`--detach`,t,u],...) // u === "refs/heads/HEAD"
Shell equivalent of the failing sequence (any fresh clone):
git rev-parse --abbrev-ref --symbolic-full-name HEAD@{u} # origin/main (upstream exists)
git rev-list --left-right --count refs/heads/HEAD...refs/remotes/origin/main # fatal: ambiguous argument ... exit 128
git worktree add --detach /tmp/x refs/heads/HEAD # fatal: invalid reference: refs/heads/HEAD
Why it sometimes "works": when the checked-out branch has no upstream (or HEAD is detached), step 2 fails and a later fallback in the same resolver picks refs/remotes/origin/HEAD (the remote's default branch tip) instead. The worktree then gets created — but from the last-fetched origin/<default>, not from the local HEAD the dialog describes, so any unpushed local commits are silently missing. That is a second bug on the same code path.
Suggested fix
Don't route the literal "HEAD" through the branch-name path. Either:
- have the stable-worktree dialog submit the real current branch / commit (
git rev-parse --abbrev-ref HEAD, orgit rev-parse HEADwhen detached), or - make the resolver special-case
HEAD: never wrap it inrefs/heads/, never queryHEAD@{u}for it, and resolve it to the localHEADcommit.
Additional information
- Possibly related: #12346 (worktree setup assumes a
mainbranch), #12685 ("Create permanent worktree" doesn't run env setup / isn't listed in Settings → Worktrees), #30954 (local branch as starting branch creates a detached worktree). - Workaround for users: create the worktree manually (
git worktree add -b <branch> <path> <base>) and add the folder as a project.
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Duplicated, closed