ruvnet/ruflo · error · Error
Git path is not valid round-trip UTF-8
Error message
Git path is not valid round-trip UTF-8
What it means
decodeGitPath round-trips the raw bytes: bytes decoded as UTF-8 must re-encode to the identical bytes. Invalid UTF-8 byte sequences (typically latin-1/cp1252 filenames from legacy systems) decode to U+FFFD replacement characters and fail the round trip. Trusting such names would hash corrupted bytes, so the harness refuses them.
Source
Thrown at v3/@claude-flow/codex/src/harness/repository-state.ts:188
}
}
function splitNul(output: Buffer): Buffer[] {
const records: Buffer[] = [];
let start = 0;
for (let index = 0; index < output.length; index += 1) {
if (output[index] !== 0) continue;
if (index > start) records.push(output.subarray(start, index));
start = index + 1;
}
if (start !== output.length) throw new Error('Git returned a non-NUL-terminated path list');
return records;
}
function decodeGitPath(bytes: Buffer): string {
const path = bytes.toString('utf8');
if (!Buffer.from(path, 'utf8').equals(bytes)) {
throw new Error('Git path is not valid round-trip UTF-8');
}
assertUnicodeScalarString(path);
if (path !== path.normalize('NFC')) {
throw new Error(`Git path is not NFC-normalized: ${path}`);
}
return normalizeRelativePath(path);
}
function normalizeRelativePath(path: string): string {
assertUnicodeScalarString(path);
if (path.includes('\\')) throw new Error(`ambiguous repository path separator: ${path}`);
const normalized = path.normalize('NFC');
if (
normalized.length === 0
|| isAbsolute(normalized)
|| normalized.startsWith('-')
|| normalized.split('/').some((part) => part === '' || part === '.' || part === '..')
) {View on GitHub (pinned to fa13ee4ad6)
Solutions
- Identify offenders: dump `git -C <repo> ls-files -z | od -c` and look for non-UTF-8 byte sequences, or scan decoded names for U+FFFD
- Rename each offender with git mv to a valid UTF-8 name
- Batch-fix whole trees with convmv: `convmv -r -f latin1 -t utf8 --notest .` (dry-run first without --notest)
- Re-extract source archives with the correct filename encoding instead of committing mangled names
Defensive patterns
Strategy: try-catch
Validate before calling
import { execFileSync } from 'node:child_process';
function findNonUtf8Paths(repoRoot: string): string[] {
const out = execFileSync('git', ['-C', repoRoot, 'ls-files', '-z'], { encoding: 'buffer' });
return out.toString('utf8').split('\u0000')
.filter((p) => p.includes('\uFFFD'));
} Type guard
function isRoundTripUtf8(path: string): boolean {
return Buffer.from(path, 'utf8').equals(Buffer.from(path, 'utf8')) && !path.includes('\uFFFD');
} Try / catch
try {
const state = captureSourceState(repoRoot);
} catch (error) {
if (error instanceof Error && error.message === 'Git path is not valid round-trip UTF-8') {
const offenders = findNonUtf8Paths(repoRoot);
throw new Error(`non-UTF-8 filenames need renaming (git mv): ${offenders.join(', ')}`);
}
throw error;
} Prevention
- Rename legacy-encoded filenames to valid UTF-8 before committing (git mv)
- Extract archives with the correct filename encoding option
- Add a CI check rejecting U+FFFD in git ls-files output
When it happens
Trigger: A tracked filename containing invalid UTF-8 bytes — created on Windows with a legacy code page, extracted from an archive with the wrong filename encoding, or written by a tool that emits raw byte names on a filesystem that permits them (ext4).
Common situations: Repos migrated from Windows machines; zip/tar extraction with mislabeled encodings; files created by older Java/Perl tools that wrote byte names; contributors on mixed-encoding systems.
Related errors
- Git returned a non-NUL-terminated path list
- Git path is not NFC-normalized: ${path}
- ambiguous repository path separator: ${path}
- case-fold repository path collision: ${prior} and ${path}
- unsupported untracked repository entry: ${path}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/112ab66c62cd3622.
Report an issue: GitHub.