ruvnet/ruflo · error · Error
ambiguous repository path separator: ${path}
Error message
ambiguous repository path separator: ${path} What it means
normalizeRelativePath rejects any repository-relative path containing a backslash. On POSIX, a backslash can be a literal filename character; on Windows, it is a directory separator — so such paths are ambiguous cross-platform and are refused before entering the source-state digest. The offending path is embedded in the message.
Source
Thrown at v3/@claude-flow/codex/src/harness/repository-state.ts:199
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 === '..')
) {
throw new Error(`unsafe repository-relative path: ${path}`);
}
return normalized;
}
function assertNoPathCollisions(paths: readonly string[]): void {
const exact = new Set<string>();
const folded = new Map<string, string>();
for (const path of paths) {
if (exact.has(path)) throw new Error(`duplicate repository path: ${path}`);
exact.add(path);View on GitHub (pinned to fa13ee4ad6)
Solutions
- git mv the offending file to a name with the backslash replaced (hyphen, underscore, or restructured with '/': 'dir/file.txt')
- Fix the generating tool to use path.posix.join for repository-relative names
- Add a CI scan of git ls-files output for the backslash character to catch regressions
Example fix
// before: Windows-style join leaks into a tracked filename
const target = `reports\\${name}.txt`; // literal backslash on POSIX
// after: POSIX separators for repository-relative paths
const target = path.posix.join('reports', `${name}.txt`); Defensive patterns
Strategy: try-catch
Validate before calling
function findBackslashPaths(paths: readonly string[]): string[] {
return paths.filter((p) => p.includes('\\'));
} Type guard
function isPosixRelativePath(path: string): boolean {
return !path.includes('\\') && !path.startsWith('-') && !path.split('/').some((part) => part === '' || part === '.' || part === '..');
} Try / catch
try {
const state = captureSourceState(repoRoot);
} catch (error) {
if (error instanceof Error && error.message.startsWith('ambiguous repository path separator')) {
const path = error.message.slice('ambiguous repository path separator: '.length);
throw new Error(`rename file containing a backslash (git mv): ${JSON.stringify(path)}`);
}
throw error;
} Prevention
- Build repository-relative paths with path.posix.join, never with backslash joins
- Fix generators from Windows environments that emit literal backslash filenames
- Scan git ls-files for backslashes in CI
When it happens
Trigger: A tracked file literally named with a backslash (e.g. a name created via shell redirection or a Windows-origin script writing 'dir\file.txt' as a single filename); tools emitting Windows-style relative paths; archives extracted with translated separators producing backslash names.
Common situations: CI steps or generators from Windows environments using backslash joins; files created by `echo x > 'a\b'` on Linux; vendored archives whose entries use backslashes.
Related errors
- Git returned a non-NUL-terminated path list
- Git path is not valid round-trip UTF-8
- Git path is not NFC-normalized: ${path}
- signBacktestArtifact: privateKey must be 32 bytes (got ${pri
- meta-proxy has no published release for ${platform}/${arch}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/f5eac9e67dcb12bb.
Report an issue: GitHub.