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
One branch whose name isn't valid UTF-8 makes every /state and /branches request for that repository fail with 502 refs-unreadable #114
RefResolver.ListAsync (RefResolver.cs L24-L40) runs git for-each-ref --format='%(objectname) %(refname)' refs/heads/ through GitRunner. GitRunner decodes stdout with strict UTF-8 (GitRunner.cs L40ff), so a single invalid byte turns the whole result into a failure. ListAsync then returns null, and both handlers answer 502 refs-unreadable (BranchStateHandler.cs L177 and around L427-L432).
Git doesn't require ref names to be UTF-8. Anyone who can push can create one, for example a branch named in Latin-1 from an older Windows client.
Reproduction
git update-ref "refs/heads/feature/$(printf 'caf\xe9')" HEAD # in the upstream; git accepts it
git clone --bare --filter=blob:none <upstream> mirror
Calling new RefResolver(new GitRunner(opts), opts).ListAsync("mirror") returns null. From then on, every /state and /branches request for that repository returns 502, including requests whose patterns never match the bad branch. The repository stays down until someone deletes the branch upstream. Clone, fetch and admission all keep succeeding, because admission discards stdout since #50, so nothing points at the cause.
Closed #50 described this exact symptom ("RefResolver returns null, and /branches and /state return refs-unreadable"). Its acceptance criteria, and the fix, covered only diff-tree and admission. The ref-listing path still has the same failure.
Suggested fix
Read for-each-ref output as raw bytes, or decode it leniently, line by line.
Skip refs whose names don't decode as UTF-8, and log a warning naming the repository and the hex of the bad name. Every other branch is still served. (A branch that can't be named in the JSON response can't be served faithfully anyway.)
Acceptance criteria
A mirror with a refs/heads/caf\xe9 branch next to main serves /state and /branches for main normally.
The bad ref is absent from the results and logged once per listing (or once per fetch).
A regression test covers this through the real GitRunner.
Priority: High. Anyone with push access can create one ref whose name isn't valid UTF-8, and every /state and /branches request for that repository then returns 502. Nothing points at the cause, because clone, fetch and admission keep succeeding, and the outage lasts until the branch is deleted upstream.
Area / suggested owner: ref listing (RefResolver.ListAsync / GitRunner stdout decoding). The fix is to decode leniently line by line, skip and log names that aren't UTF-8, and add a regression test through the real GitRunner.
Activity
matt-edmondson commentedon Nov 1, 2026
Triage
/stateand/branchesrequest for that repository then returns 502. Nothing points at the cause, because clone, fetch and admission keep succeeding, and the outage lasts until the branch is deleted upstream.RefResolver.ListAsync/GitRunnerstdout decoding). The fix is to decode leniently line by line, skip and log names that aren't UTF-8, and add a regression test through the realGitRunner.?and[...]disagree withgit branch --liston non-ASCII names:origin/?matchesorigin/éhere but not in git #115 is a separate non-ASCII bug in pattern matching, not a duplicate. It would be efficient to work on both together. A partly deleted or corrupt mirror is never re-cloned or reaped, so that repository returns 502 until someone deletes it by hand #58 also covers 502s that don't recover, but from a different cause.Generated by Claude Code
Move the #114 end-to-end test to the end of StateFlowTests