ruvnet/ruflo · error · Error
malformed Git index record
Error message
malformed Git index record
What it means
submoduleStates() parses the output of `git ls-files --stage -z`; each record must contain a tab (0x09) separating '<mode> <sha> <stage>' metadata from the path. A record with no tab means the output does not match the expected git format, so parsing aborts with 'malformed Git index record'.
Source
Thrown at v3/@claude-flow/codex/src/harness/repository-state.ts:302
return { digest: digest(canonicalJson(entries)), entries };
}
function trackedPatch(repoRoot: string): ContentDigest {
return contentDigest(gitBuffer(repoRoot, [
'diff',
'--binary',
'--full-index',
'--no-ext-diff',
'HEAD',
'--',
]));
}
function submoduleStates(repoRoot: string): readonly SubmoduleState[] {
const staged = splitNul(gitBuffer(repoRoot, ['ls-files', '--stage', '-z']));
const submodules = staged.flatMap((entry): Array<{ path: string; commit: string }> => {
const tab = entry.indexOf(0x09);
if (tab < 0) throw new Error('malformed Git index record');
const metadata = entry.subarray(0, tab).toString('ascii');
const match = /^160000 ([0-9a-f]+) [0-3]$/.exec(metadata);
return match?.[1]
? [{ path: decodeGitPath(entry.subarray(tab + 1)), commit: match[1] }]
: [];
});
assertNoPathCollisions(submodules.map(({ path }) => path));
return submodules.map(({ path, commit }): SubmoduleState => {
const absolute = resolve(repoRoot, path);
assertInsideRepository(repoRoot, absolute);
const actualCommit = optionalGitText(absolute, ['rev-parse', '--verify', 'HEAD']);
if (!actualCommit) {
return {
path,
initialized: false,
expectedCommit: commit,
trackedPatch: contentDigest(Buffer.alloc(0)),View on GitHub (pinned to fa13ee4ad6)
Solutions
- Run `git ls-files --stage` manually and inspect the raw output for records without a tab
- Rebuild the index: `rm .git/index && git reset`
- Upgrade git to a current stable release and remove any git shims/aliases from PATH
Defensive patterns
Strategy: try-catch
Validate before calling
const records = execFileSync('git', ['-C', root, 'ls-files', '--stage', '-z']);
for (const rec of splitNul(records)) if (!rec.includes(0x09)) throw new Error('unexpected git output shape'); Try / catch
try { capture(); } catch (e) { if (/malformed Git index record/.test(String(e))) { rebuildIndexOrUpgradeGit(); } throw e; } Prevention
- Pin a current stable git version in CI and devcontainers
- Avoid git shims/wrappers that rewrite plumbing output
- Run git fsck after crashes
When it happens
Trigger: A git version or wrapper that emits `ls-files --stage` output in a different shape; a corrupted index producing garbage records; output mangled by GIT_EXTERNAL_DIFF/aliases or a shim in front of git.
Common situations: Very old or exotic git builds, git installed via wrappers (hub, containers, busybox git), or a .git/index corrupted by a crash — the regex/tab contract silently breaks.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- duplicate repository path: ${path}
- Invalid git ref: contains unsafe characters
- Invalid git ref: suspicious pattern
- Invalid git ref: too long
- Invalid CFP file: ${e instanceof Error ? e.message : String(
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/cf0a184be0054697.
Report an issue: GitHub.