You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A git timeout or failure is reported as "no-merge-base" or 409 "unknown-base" (and counted in unknown_base) instead of as a timeout or server error #69
MirrorQueries collapses every git failure into a negative answer:
ContainsCommitAsync (GitBranchStateCache/Mirrors/MirrorQueries.cs:47-52) returns result.Succeeded. A timed-out or crashed cat-file -e therefore reads as "commit not in mirror".
FindMergeBaseAsync (MirrorQueries.cs:72-78) returns null on any non-success. That includes TimedOut and exit 128 from a corrupt or locked repository.
BranchStateHandler then reports these to the client as data facts:
:182-194: a false ContainsCommitAsync becomes 409 unknown-base and increments the unknown_base metric.
:239-244: a null merge base becomes a branch entry with error: "no-merge-base".
The diff path already distinguishes these cases through DiffOutcome.Timeout. The commit check and merge-base queries don't.
Failure scenario
Reproduced at HEAD cbd20fc by adding a temporary timeout flag to ScriptedGit and two integration tests:
merge-base times out (a large repo going over DiffTimeout): 200 {"branches":[{"name":"origin/main",...,"mergeBase":null,"error":"no-merge-base"}],"partial":true}
cat-file -e times out (over ProbeTimeout, or a corrupt mirror): 409 {"error":"unknown-base","message":"The mirror does not hold that commit..."}
The client is told its histories are unrelated, or that its base commit was never pushed. A client following the documented contract might act on that, for example by pushing again or dropping the branch. On the server side, unknown_base rises, and README:169 names that counter as the one to alert on, so a service fault (slow disk, corrupt mirror) is misread as client behaviour.
Suggested fix
Return a three-state result from both queries: Found / Absent / Failed(TimedOut). Treat only exit code 1 as absent: git merge-base exits 1 for unrelated histories, and git cat-file -e exits 1 for a missing object. Every other outcome is a failure.
In BranchStateHandler:
Map a merge-base timeout to the branch-level timeout error the diff path already uses, and any other failure to a distinct error.
Map a failed commit check to 504 (timeout) or 502 (other), not 409, and don't increment unknown_base.
Acceptance criteria
With merge-base timing out, the branch reports error: "timeout", not no-merge-base.
With cat-file timing out or failing, the response is 5xx and unknown_base is unchanged.
A genuinely missing commit (exit 1) still returns 409 unknown-base, and genuinely unrelated histories still report no-merge-base.
Priority: High. Service faults (timeouts, corrupt mirrors) are reported to clients as facts about the data (unknown-base, no-merge-base). A client may act on that, for example by pushing again or dropping a branch, and it also inflates the unknown_base counter the README says to alert on.
Area / suggested owner:Mirrors/MirrorQueries.cs plus BranchStateHandler response mapping (@matt-edmondson).
Activity
matt-edmondson commentedon Oct 5, 2026
Triage
unknown-base,no-merge-base). A client may act on that, for example by pushing again or dropping a branch, and it also inflates theunknown_basecounter the README says to alert on.Mirrors/MirrorQueries.csplusBranchStateHandlerresponse mapping (@matt-edmondson).unknown-basepath, so they could be fixed together.Generated by Claude Code