affaan-m/ECC · error · ValueError
reference source mutated during media probing
Error message
reference source mutated during media probing
What it means
TasteForge hashes each reference media file, snapshots it, runs the media probe on the snapshot, then re-hashes the original file to bind the recorded SHA-256 to the exact bytes probed. This ValueError is raised when the post-probe re-check shows the source file's size, mtime, inode metadata, or content digest changed while probing was running. It is a fail-closed integrity guard: the run aborts instead of emitting provenance that does not match the real file.
Solutions
- Wait until the reference file is fully written (e.g. finish the download/export, ensure the writer process has closed the file), then re-run run_workflow.
- Exclude the reference directory from active cloud-sync/indexer activity, or pause sync while the workflow runs.
- Copy references into a stable, workflow-owned input directory and point the config at those copies.
- Re-run the workflow; this is a transient concurrency condition, and a retry on an untouched file will pass.
- If the mutation is intentional, regenerate downstream artifacts that consumed the old digest so provenance and file bytes stay consistent.
Example fix
// before: probing a file that a downloader is still writing
references = ["assets/clip.mp4"] # clip.mp4 still being written by ffmpeg
// after: wait for the writer to finish before running
subprocess.run(["ffmpeg", ...], check=True)
while is_still_growing("assets/clip.mp4"):
time.sleep(1) # size stable across two stats
run_workflow("contract.json", "out/") Defensive patterns
Strategy: retry
Validate before calling
import os, time
def source_is_stable(path, interval=1.0, checks=2):
stats = []
for _ in range(checks):
st = os.stat(path)
stats.append((st.st_dev, st.st_ino, st.st_size, st.st_mtime_ns))
time.sleep(interval)
return len(set(stats)) == 1
# call before run_workflow
if not source_is_stable("assets/clip.mp4"):
raise RuntimeError("reference still changing; wait before probing") Type guard
def is_quiescent_file(path: str) -> bool:
import os, time
s1, s2 = os.stat(path), None
time.sleep(1.0)
s2 = os.stat(path)
return (s1.st_size, s1.st_mtime_ns, s1.st_ino) == (s2.st_size, s2.st_mtime_ns, s2.st_ino) Try / catch
import time
from skills.taste_application.scripts.tasteforge.workflow import run_workflow
for attempt in range(3):
try:
return run_workflow("contract.json", "out/")
except ValueError as e:
if "mutated during media probing" not in str(e):
raise
time.sleep(2 ** attempt) # back off, let writers finish
raise RuntimeError("reference file kept changing; pause writers/sync and retry") Prevention
- Freeze reference media into a dedicated input directory before running the workflow
- Pause cloud-sync clients (Dropbox/Drive) over asset directories during runs
- Wait for downloads/exports to fully complete (stable size across two stats) before probing
- Run the workflow off the live asset tree; copy, then probe the copy
When it happens
Trigger: run_workflow() -> _stable_probe(path, probe) on a reference file that is modified, appended to, truncated, or re-saved by another process (or by the user's own editor/sync tool) between the initial snapshot and the final fstat/hash re-check.
Common situations: Cloud sync clients (Dropbox/Drive/OneDrive) rewriting files mid-run; a video editor or download manager still writing the reference file; a build step or asset pipeline that touches/copies references concurrently; cron jobs regenerating assets while the workflow runs.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Another Nasiko lifecycle operation won lock acquisition
- Another Nasiko lifecycle operation won stale-lock recovery
- capsule.lock_lost
- dispatch transition lost
- Legacy sync path changed before removal
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/eddca7c98a91135a.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/workflow.py:109
os.close(snapshot_fd)
source_digest = digest.hexdigest()
copied = os.fstat(descriptor)
if (before.st_dev, before.st_ino, before.st_size, before.st_mtime_ns) != (
copied.st_dev, copied.st_ino, copied.st_size, copied.st_mtime_ns
):
raise ValueError("reference source mutated while creating stable snapshot")
verified_size, verified_digest = _hash_descriptor(descriptor)
if verified_size != total or verified_digest != source_digest:
raise ValueError("reference source mutated while creating stable snapshot")
measured = probe(snapshot)
after = os.fstat(descriptor)
final_size, final_digest = _hash_descriptor(descriptor)
if (before.st_dev, before.st_ino, before.st_size, before.st_mtime_ns) != (
after.st_dev, after.st_ino, after.st_size, after.st_mtime_ns
) or final_size != total or final_digest != source_digest:
raise ValueError("reference source mutated during media probing")
rebound = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
try:
rebound_stat = os.fstat(rebound)
if (rebound_stat.st_dev, rebound_stat.st_ino) != (before.st_dev, before.st_ino):
raise ValueError("reference source identity changed during media probing")
finally:
os.close(rebound)
return measured, total, source_digest
finally:
os.close(descriptor)
def _finite_real(value: Any) -> bool:
return isinstance(value, (int, float)) and not isinstance(value, bool) and math.isfinite(value)
def _validate_probe(measured: dict[str, Any]) -> float:
def require_finite_evidence(value: Any) -> None:View on GitHub (pinned to 8321021c54)