abhigyanpatwari/GitNexus · error · Error
Analyzer identity directory changed while it was read: ${can
Error message
Analyzer identity directory changed while it was read: ${candidate} What it means
Analyzer identity fingerprinting double-snapshots each directory (stat state before and after listing entries) and retries once internally; if both attempts observe the directory changing mid-read, it gives up and throws. It is a TOCTOU guard: the identity digest must be computed from a stable view of the build/dependency directories, so concurrent mutation makes the result untrustworthy.
Source
Thrown at gitnexus/src/core/analyzer-identity.ts:517
for (const entry of entries) updateCanonicalFrame(hash, [entry.name, entry.kind]);
return `sha256:${hash.digest('hex')}`;
}
function directoryEntriesDigest(candidate: string): string {
return directoryEntriesDigestFrom(readdirSync(candidate, { withFileTypes: true }));
}
function snapshotDirectoryInventory(candidate: string): {
state: StatState;
entriesDigest: string;
} {
for (let attempt = 0; attempt < 2; attempt += 1) {
const before = snapshotDirectory(candidate);
const entriesDigest = directoryEntriesDigest(candidate);
const after = snapshotDirectory(candidate);
if (isDeepStrictEqual(before, after)) return { state: after, entriesDigest };
}
throw new Error(`Analyzer identity directory changed while it was read: ${candidate}`);
}
function readStableFile(candidate: string): { bytes: Buffer; state: ReadableFileState } {
for (let attempt = 0; attempt < 2; attempt += 1) {
const before = snapshotReadableFile(candidate);
const bytes = readFileSync(candidate);
const after = snapshotReadableFile(candidate);
if (isDeepStrictEqual(before, after)) return { bytes, state: after };
}
throw new Error(`Analyzer identity input changed while it was being read: ${candidate}`);
}
function readStableFileWithinBudget(
candidate: string,
budget: RuntimeArtifactScanBudget,
maxBytes: number,
): { bytes: Buffer; state: ReadableFileState } {
const before = snapshotReadableFile(candidate);View on GitHub (pinned to aac7515d2a)
Solutions
- Simply re-run analyze — the error is transient and single-shot interference almost never repeats
- Serialize the work: finish installs/builds (or cancel watchers) before invoking analyze; don't run two analyze processes on the same tree
- For Docker bind mounts, prefer named volumes or run analyze before mounting, to avoid mtime churn from host sync
- If it recurs, identify the writer: lsof +D <path> or check what regenerates the directory during the run
Defensive patterns
Strategy: retry
Try / catch
for (let attempt = 1; attempt <= 3; attempt += 1) {
try {
return await computeAnalyzerIdentity(request);
} catch (err) {
const msg = (err as Error).message ?? '';
const transient = msg.includes('changed while it was read');
if (!transient || attempt === 3) throw err;
await delay(250 * attempt); // let the concurrent writer finish
}
} Prevention
- Run analyze after installs/builds complete, not concurrently with them
- Never run two analyze processes against the same checkout at once
- Pause file watchers / hot-rebuild loops during indexing
- Treat this error as environmental: if it recurs, find the process mutating the fingerprinted directories (lsof +D <path>)
When it happens
Trigger: Running analyze while a build, npm/yarn/pnpm install, code generator, formatter-on-save, or another gitnexus process is writing into the directories being fingerprinted (the analyzer build root and dependency directories); hot rebuild loops with tight write cadence can defeat both attempts.
Common situations: CI running analyze in parallel with an install step or a bundler watch; local dev with a file watcher regenerating outputs continuously; two analyze runs racing on the same checkout; Docker bind mounts with slow metadata sync flipping mtimes during the snapshot.
Related errors
- Analyzer vendored runtime directory is unavailable: ${vendor
- Analyzer build changed while its identity was being computed
- Analyzer identity input changed while it was being read: ${c
- Analyzer runtime scan exceeded ${maxBytes} bytes: ${candidat
- Analyzer identity input changed while it was being hashed: $
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/f5ea3c49d16f1545.
Report an issue: GitHub.