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

  1. 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.
  2. Exclude the reference directory from active cloud-sync/indexer activity, or pause sync while the workflow runs.
  3. Copy references into a stable, workflow-owned input directory and point the config at those copies.
  4. Re-run the workflow; this is a transient concurrency condition, and a retry on an untouched file will pass.
  5. 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

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


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)