abhigyanpatwari/GitNexus · error · ValueError
workspace file changed while hashing: {entry.path}
Error message
workspace file changed while hashing: {entry.path} What it means
Raised in workspace_snapshot (runner_artifacts.py:181) after hashing a file: os.fstat is taken again and if size or mtime_ns changed between the pre-hash fstat and the post-hash fstat the file is considered mutated during hashing. The guard ensures the computed sha256 actually corresponds to stable content; a mid-read change would yield a meaningless hash.
Source
Thrown at eval/workflow_bench/runner_artifacts.py:181
continue
file_bytes += metadata.st_size
if file_bytes > MAX_WORKSPACE_SNAPSHOT_FILE_BYTES:
raise ValueError("workspace snapshot exceeds its bounded file-byte limit")
descriptor = os.open(entry.path, os.O_RDONLY | nofollow)
try:
opened = os.fstat(descriptor)
if (
not stat.S_ISREG(opened.st_mode)
or opened.st_dev != metadata.st_dev
or opened.st_ino != metadata.st_ino
):
raise ValueError(f"workspace file changed while opening: {entry.path}")
digest = hashlib.sha256()
while chunk := os.read(descriptor, 64 * 1024):
digest.update(chunk)
after = os.fstat(descriptor)
if (opened.st_size, opened.st_mtime_ns) != (after.st_size, after.st_mtime_ns):
raise ValueError(f"workspace file changed while hashing: {entry.path}")
finally:
os.close(descriptor)
snapshot[relative.as_posix()] = f"f:{permissions:o}:{metadata.st_size}:{digest.hexdigest()}"
return snapshot
def enforce_phase_workspace(
worktree: Path,
before: dict[str, str],
*,
allowed_artifact: Path,
) -> None:
"""Require a phase to change only its one explicit workspace artifact."""
root = worktree.expanduser().absolute()
artifact = allowed_artifact.expanduser().absolute()
try:
relative = PurePosixPath(artifact.relative_to(root).as_posix())View on GitHub (pinned to d540b00184)
Solutions
- Ensure the phase is quiescent before snapshotting — the model/build must have exited and flushed. Check for stray processes writing to the worktree (lsof +D <worktree>).
- If the file is a live log, exclude it by moving it under a bootstrap-noise path or out of the worktree.
- Re-run the snapshot; transient concurrency races usually clear once the writer is gone.
Defensive patterns
Strategy: try-catch
Try / catch
try:
snapshot = workspace_snapshot(root)
except ValueError as exc:
if "changed while hashing" in str(exc):
# File was appended/truncated during the read loop.
wait_for_quiescence(root)
snapshot = workspace_snapshot(root)
else:
raise Prevention
- Ensure no log/daemon is appending to files in the worktree during the snapshot.
- Move live logs outside the hashed tree.
- Take the snapshot at a true phase boundary where the writer has exited.
When it happens
Trigger: A process writes to the file while os.read loops over its 64 KiB chunks: between the pre-read fstat (line 169) and the post-read fstat (line 179) either st_size or st_mtime_ns differs. Happens when a log file, build output, or model artifact is appended to during the snapshot.
Common situations: A task is still writing logs/output when the phase-boundary snapshot runs; an editor autosaving; a daemon appending to a file inside the worktree; concurrent arms sharing a directory they should not.
Related errors
- workspace file changed while opening: {entry.path}
- oracle source changed while being captured: {relative}
- oracle stage root changed during verification
- oracle stage parent changed during verification: {item.targe
- oracle file changed during verification: {item.target}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/2ad052620d063c9b.
Report an issue: GitHub.