ruvnet/ruflo · error · Error
Git status reported changes that exact-state capture could n
Error message
Git status reported changes that exact-state capture could not identify
What it means
The porcelain status was non-empty, yet the exact-state capture found nothing dirty: no tracked patch bytes, no untracked manifest entries, no dirty submodules. Rather than emit a sourceStateId for an unattributable state, the harness throws. It is a consistency guarantee between `git status` and the content-level capture.
Source
Thrown at v3/@claude-flow/codex/src/harness/repository-state.ts:460
baseCommit,
treeId,
sourceStateId: digest(canonicalJson(identity)),
};
}
repositoryPaths(repoRoot, true);
const first = captureContentState(repoRoot);
const second = captureContentState(repoRoot);
if (canonicalJson(first) !== canonicalJson(second)) {
throw new Error('repository changed while capturing exact source state');
}
const repository = repositoryIdentity(repoRoot);
const dirty = second.trackedPatch.bytes > 0
|| second.untrackedManifest.entries.length > 0
|| second.submodules.some(hasDirtySubmodule);
if (!dirty) throw new Error('Git status reported changes that exact-state capture could not identify');
const identity = {
version: 1,
scope: 'git-visible',
repositoryId: repository.repositoryId,
baseCommit: second.baseCommit,
tree: second.treeId,
trackedPatch: second.trackedPatch,
untrackedManifest: second.untrackedManifest,
submodules: second.submodules,
};
return {
version: 1,
scope: 'git-visible',
kind: 'dirty',
clean: false,
repository,
baseCommit: second.baseCommit,View on GitHub (pinned to fa13ee4ad6)
Solutions
- Run `git update-index --refresh` (or a no-op `git status` then `git diff`) to settle stat info, then retry
- Check submodule noise: `git submodule status` and diff `git config -f .gitmodules`
- If a submodule is only config-dirty, set `submodule.<name>.ignore = dirty` or commit the submodule pointer change
Example fix
# settle racy stat info, then re-capture git update-index --refresh || true git status --porcelain # should now match actual content # re-run the capture command
Defensive patterns
Strategy: validation
Validate before calling
import { execSync } from 'node:child_process';
execSync('git update-index -q --refresh', { cwd: root });
const status = execSync('git status --porcelain', { cwd: root, encoding: 'utf8' });
const diff = execSync('git diff --binary --full-index HEAD', { cwd: root, encoding: 'buffer' });
const attributable = diff.length > 0 || /\?\?/.test(status); Try / catch
try { return capture(root); }
catch (e) {
if (/could not identify/.test(String(e))) { execSync('git update-index --refresh', { cwd: root }); return capture(root); }
throw e;
} Prevention
- Run `git update-index --refresh` after checkouts/touches before capturing
- Set submodule ignore=dirty for config-only-dirty submodules or commit pointer changes
- Avoid touching files (mtime churn) right before snapshots
When it happens
Trigger: Stat-dirty files: mtime/inode changes with identical content so `git status` reports modified but `git diff --binary` is empty; submodule status noise (modified config vs content); racy-git after checkouts or touches; files ignored by diff drivers.
Common situations: Running `touch src/**` or a checkout that rewrites mtimes right before capture; submodules whose status differs only by config (ignore=dirty settings); CI caching that restores mtimes incorrectly.
Related errors
- Git-visible source state does not match the build evidence r
- Git-visible source state changed before build evidence recom
- unsafe repository-relative path: ${path}
- repository path escapes root: ${candidate}
- unsupported untracked repository entry: ${path}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/fd3628f389f6d58f.
Report an issue: GitHub.