Skip to content

Skip a branch whose name is not UTF-8 instead of failing every ref listing [patch] - #118

Merged
matt-edmondson merged 2 commits into
mainfrom
fix/114-skip-undecodable-refs
Nov 4, 2026
Merged

matt-edmondson merged 2 commits into
mainfrom
fix/114-skip-undecodable-refs

Conversation

@matt-edmondson

@matt-edmondson matt-edmondson commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #114

What changes

RefResolver.ListAsync read for-each-ref output through GitRunner's strict UTF-8 decoding. Git allows a ref name that isn't valid UTF-8, such as a Latin-1 caf\xe9, and one of those failed the whole listing. Every /state and /branches request for the repository then returned 502 refs-unreadable until someone deleted the branch upstream.

  • GitInvocation.ReadStandardOutputAsBytes (new): when set, GitRunner decodes stdout as Latin-1, so each character is the byte git wrote. Every other command keeps strict UTF-8.
  • RefResolver sets the flag for for-each-ref. The new DecodeLines turns each line back into bytes and decodes it as strict UTF-8 on its own. A line that doesn't decode is dropped, and the rest go to the existing Parse.
  • Each dropped ref is logged once per listing as a warning (RefLog.UndecodableRefSkipped, event 4000). The log names the mirror directory and the hex bytes of the ref name. RefResolver takes an optional ILogger<RefResolver>, which DI supplies, and existing constructions keep working.

A ref is skipped rather than served with a replacement character because the name can't be written into a JSON response faithfully. It would look fine and match nothing the client has.

Tests

  • RealRepositoryTests.RefResolver_ABranchNameThatIsNotUtf8_IsSkipped uses the real GitRunner against a bare mirror. The mirror has refs/heads/feature/caf\xe9 written into packed-refs, next to main and feature/ui. The listing must succeed, keep the other branches, leave out the bad one, and log exactly one warning carrying its hex.
  • StateFlowTests.ABranchNameThatIsNotUtf8_IsSkipped_AndEveryOtherBranchIsStillServed: /branches?pattern=origin/* returns 200 with only the UTF-8 branches, and /state for origin/main returns 200. ScriptedGit now fails strict-mode for-each-ref the way GitRunner does when it holds a non-UTF-8 ref.
  • RefResolverTests.DecodeLines_DropsOnlyTheLineThatIsNotUtf8: drops a lone 0xE9 and keeps a correctly encoded é.

With the flag turned off in RefResolver, the real-git test and the end-to-end test both fail. With it on, the full GitBranchStateCache.Tests suite passes (288/288, net10.0).

This branch is independent of #117. The end-to-end test goes at the end of StateFlowTests, away from the lines #117 adds, and git merge-tree confirms the two branches merge cleanly in either order.

🤖 Generated with Claude Code

https://claude.ai/code/session_017vfJW24ManL6mVAsf34qvT

…sting [patch]

RefResolver.ListAsync read for-each-ref output through GitRunner's strict
UTF-8 decoding, so one ref name git allows but UTF-8 cannot read failed
the whole listing, and every /state and /branches request for that
repository returned 502 refs-unreadable until the branch was deleted.

GitInvocation.ReadStandardOutputAsBytes now returns stdout one character
per byte. RefResolver decodes each line on its own, skips a line that is
not UTF-8, and logs a warning with the hex of the ref name. Every other
branch is still served.

Fixes #114

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW24ManL6mVAsf34qvT
Keeps it clear of the lines #117 adds, so the two PRs merge in either order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW24ManL6mVAsf34qvT
@sonarqubecloud

sonarqubecloud Bot commented Nov 3, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 4f90ced into main Nov 4, 2026
15 checks passed
@matt-edmondson
matt-edmondson deleted the fix/114-skip-undecodable-refs branch November 4, 2026 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

One branch whose name isn't valid UTF-8 makes every /state and /branches request for that repository fail with 502 refs-unreadable

2 participants