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
Status()/Diff()/Patch() throw for the whole repo when any path contains <, > or |, or is longer than 256 characters (legal on Linux/macOS) #131
Every path git reports goes through GitParseValues.ToRelativeFilePath. That covers 5 call sites in GitStatusParser, 3 in GitDiffParser and 3 in GitPatchParser, and each converts the path with RelativeFilePath.TryCreate from ktsu.Semantics.Paths.
That validation applies Windows-only rules:
Characters:<, > and | are rejected. Checking ASCII 1–127 shows these three are the only characters rejected.
Length: any path of 257 or more characters is rejected (256: True, 257: False).
Linux and macOS allow all of these characters, and git handles long paths without trouble (Linux PATH_MAX is 4096). When one path fails validation, the parser throws, and the whole verb fails.
Failure scenarios
A. Create x|y.txt in a repository (a valid filename on Linux/macOS), then call repo.Status():
GitParseException: git reported a path that cannot be represented as a relative file path: 'x|y.txt'.
After committing the file and then modifying it, Diff() and Patch() fail the same way.
B. Stage a file whose repository-relative path is 274 characters long, for example dir/ repeated 30 times followed by 150 ys and .txt. Status() throws the same GitParseException. Deep Java and JavaScript source trees reach this length.
In both cases one such file anywhere in the working tree makes Status() unusable for the entire repository. It does not just drop that one entry.
Suggested fix / acceptance criteria
Preferred: carry repository paths in a git-specific semantic type that forbids only what git forbids: NUL, absolute paths, and .. escapes. Reserve the OS-specific RelativeFilePath validation for the point where a caller actually touches the local file system.
Alternative: fix ktsu.Semantics.Paths upstream so that it does not apply Windows reserved-character and MAX_PATH rules on POSIX.
Tests: add tests showing that Status(), Diff() and Patch() return entries for x|y.txt, a<b>.txt and a path longer than 260 characters on non-Windows platforms.
Priority: High. On Linux and macOS, one file with <, > or | in its name, or one path over 256 characters, makes Status(), Diff() and Patch() throw for the entire repository. Deep JS/Java trees reach that length routinely, so this blocks the library's core verbs on non-Windows platforms.
Area / suggested assignee:GitParseValues.ToRelativeFilePath, which feeds every path in GitStatusParser, GitDiffParser and GitPatchParser. The root cause is Windows-only validation in ktsu.Semantics.Paths. Owner: @matt-edmondson
Next step: decide once for the org whether Semantics.Paths should stop applying Windows rules on POSIX. That one upstream fix would close this and FileDeduplicator#140 together. If it can't land soon, use the git-specific path type proposed in the issue here, and add the x|y.txt, a<b>.txt and >260-character tests.
The alternative is chosen: fix ktsu.Semantics.Paths upstream so that it does not apply Windows reserved-character and MAX_PATH rules on POSIX. A git-specific path type in this repo is not being added. This follows the org-wide reuse rule "prefer reuse, accept costs; fix gaps upstream" (Cross-library reuse audit log .github#15).
Next reader: blocked on the Semantics.Paths fix. When I checked, no matching open issue existed in ktsu-dev/Semantics, so file one there first and link it here and on FileDeduplicator#140 (related: Essentials#48). Once it ships, bump the dependency and add the x|y.txt, a<b>.txt and >260-character tests for Status()/Diff()/Patch().
Filed the upstream fix as ktsu-dev/Semantics#330. The POSIX tests described there (x|y.txt, a<b>.txt, a path over 260 characters through Status()/Diff()/Patch()) follow once it ships.
Activity
matt-edmondson commentedon Sep 27, 2026
Triage
<,>or|in its name, or one path over 256 characters, makesStatus(),Diff()andPatch()throw for the entire repository. Deep JS/Java trees reach that length routinely, so this blocks the library's core verbs on non-Windows platforms.GitParseValues.ToRelativeFilePath, which feeds every path inGitStatusParser,GitDiffParserandGitPatchParser. The root cause is Windows-only validation inktsu.Semantics.Paths. Owner: @matt-edmondson<,>or|in its name or a path over 256 characters FileDeduplicator#140 (every verb crashes on the same characters and path lengths) and is related to FileSystem/DataHome/ConfigHome/Temp persistence can't store non-ASCII keys of ~83+ chars on Linux/macOS: StoreAsync throws PathTooLongException Essentials#48 (PathTooLongException on POSIX). No open PR in GitIntegration touches path conversion; Pin context lines and rename detection in Patch() #128 and Read quoted and " b/"-containing paths in Patch() headers #129 are about Patch() headers.Semantics.Pathsshould stop applying Windows rules on POSIX. That one upstream fix would close this and FileDeduplicator#140 together. If it can't land soon, use the git-specific path type proposed in the issue here, and add thex|y.txt,a<b>.txtand >260-character tests.Generated by Claude Code
matt-edmondson commentedon Sep 28, 2026
Decision (maintainer, 2026-09-28)
ktsu.Semantics.Pathsupstream so that it does not apply Windows reserved-character and MAX_PATH rules on POSIX. A git-specific path type in this repo is not being added. This follows the org-wide reuse rule "prefer reuse, accept costs; fix gaps upstream" (Cross-library reuse audit log .github#15).<,>or|in its name or a path over 256 characters FileDeduplicator#140 has the same root cause and may still fix locally in the meantime. This repo waits for the upstream fix.Next reader: blocked on the
Semantics.Pathsfix. When I checked, no matching open issue existed in ktsu-dev/Semantics, so file one there first and link it here and on FileDeduplicator#140 (related: Essentials#48). Once it ships, bump the dependency and add thex|y.txt,a<b>.txtand >260-character tests forStatus()/Diff()/Patch().Generated by Claude Code
matt-edmondson commentedon Sep 29, 2026
Filed the upstream fix as ktsu-dev/Semantics#330. The POSIX tests described there (
x|y.txt,a<b>.txt, a path over 260 characters throughStatus()/Diff()/Patch()) follow once it ships.Generated by Claude Code