Description
This was generated by AI during triage.
What happened
A Spec run ended as a Failed spec run with Tickets not done: #1348, #1349. Neither Ticket had done any work: both Runs failed three seconds after starting, before creating a worktree or starting a session. The other three Tickets started at the same moment landed normally.
One Ticket blocked the other five. When it merged into the Spec branch, the five unblocked Tickets started at once, and each Ticket's Run fetched the Spec branch in the shared Launch directory. Every fetch tried to move the same remote-tracking ref from the same old commit to the same new one. One won; two of the others failed:
12:43:36 starting #1348
12:43:36 starting #1349
12:43:36 starting #1350
12:43:36 starting #1351
12:43:36 starting #1352
12:43:39 #1349: git fetch origin issue-1346 failed: From https://github.com/<owner>/<repo>
12:43:39 #1349: * branch issue-1346 -> FETCH_HEAD
12:43:39 #1349: 93d814703..8cf48f061 issue-1346 -> origin/issue-1346
12:43:39 #1349: error: fetching ref refs/remotes/origin/issue-1346 failed: incorrect old value provided
12:43:39 #1349 failed
Two defects
1. The race is not retried. thirdshift already retries a git command that fails because another git moved a ref it was updating, but it recognises that only by git's older wording (cannot lock ref … but expected). git 2.52 reports the same race as fetching ref <ref> failed: incorrect old value provided, which is not recognised, so the fetch fails outright. A second attempt would have been a no-op and succeeded.
2. The reported cause hides the error. The Ticket's line in the end-of-run summary, the Tickets checklist and the Run notification kept only the first line of the cause:
#1348 failed: git fetch origin issue-1346 failed: From https://github.com/<owner>/<repo>
For a failed git command the first line of stderr is often a banner like From …; git's own error: line came last and was dropped.
Reproduction
git 2.52.0. In a clone, with origin's branch spec one commit ahead of the clone's origin/spec, run five git fetch origin spec at once in that clone. Over 40 rounds, four of the five failed every time, each with the stderr above. On the real run, network timing let three of five through.
Impact
Any Spec where one Ticket blocks two or more others hits this when the blocker lands, on a host with a recent git. The same unlocked fetches of a shared remote-tracking ref also happen later in a Run, from each Run's worktree, where losing the race would fail a Run whose session had already finished.
Activity
JacobStephens2 commentedon Oct 2, 2026
Agent Brief
Category: bug
Summary: Retry a git command that loses a ref-update race as newer git words it, and report a failed git command's cause by git's own error line
Current behavior:
Git::runruns a failed command again, for a bounded time, while its stderr says another git holds a lock file or moved a ref between reading and updating it. That check (held_lock) knows the race only ascannot lock ref … but expected. git 2.52 reports it aserror: fetching ref refs/remotes/origin/<branch> failed: incorrect old value provided, so concurrent fetches of one branch from Runs sharing a Launch directory fail instead of being retried. In a Spec run this fails Tickets that had not started any work.Separately, a failed git command's error is
git <args> failed:followed by the last lines of its stderr, then stdout, in the order git wrote them. A child Run's cause is read back by what started it as its first line only, and that line is what the Ticket's summary line, the Tickets checklist and the Run notification show. For a failed fetch the first line is theFrom <url>banner, and git'serror:line, which says what went wrong, is dropped.Desired behavior:
incorrect old value providedon stderr is treated like the other cases of a ref another git moved meanwhile: run again within the same bounded wait, and failing as now only if it still fails once the wait is over. The older wordings keep being recognised.error:orfatal:, the first such line followsgit <args> failed:on the first line of the message. Nothing git wrote is lost: the rest of the reported lines still follow, within the existing limit on how many lines are kept. A failure with no such line, such as a hook's explanation on stdout or no output at all, reads as it does today.Key interfaces:
Git::run: its retry condition and the message it fails with. Its signature does not change.held_lock: recognises the new wording as well.ChildFailure::cause, "the first line of its cause") is unchanged; the fix is that a git failure's first line is now the informative one.Acceptance criteria:
error: fetching ref refs/remotes/origin/main failed: incorrect old value providedon stderr is run again and succeeds, alongside the existing test for thecannot lock ref … but expectedwordingFrom …banner, ref lines, then anerror:line produces a message whose first line isgit <args> failed: error: …, with the other lines still present#<n> failed: git fetch origin <branch> failed: error: …cargo testandcargo clippypassOut of scope: