affaan-m/ECC · error · ValueError

Bundle changed during validation

Error message

Bundle changed during validation

What it means

The library fingerprints receipt.json before and after reading the manifests; if the receipt's fingerprint differs from the binding computed at bundle open, the bundle was modified concurrently during validation and results can't be trusted.

Solutions

  1. Re-run validation once the bundle is quiescent (no writers active)
  2. Lock or serialize the pipeline so nothing writes to the bundle during validation
  3. Exclude the bundle directory from live sync/backup tools during validation runs

Example fix

// before
validate_assets(...)  # while generation job still writing to bundle
// after
wait_for_generation_job_to_finish(); validate_assets(...)
Defensive patterns

Strategy: retry

Try / catch

for attempt in range(3):
    try:
        return validate_assets(assets, bundle_root=root)
    except ValueError as e:
        if str(e) == "Bundle changed during validation" and attempt < 2:
            wait_until_bundle_quiescent(root); continue
        raise

Prevention

When it happens

Trigger: Another process writing to the bundle (regenerating artifacts, updating receipts) while validate_assets or ingest_assets is running; a watcher/sync tool touching receipt.json mid-validation.

Common situations: Running validation while a generation pipeline is still emitting into the same bundle directory; Dropbox/OneDrive sync replacing files during a read; two CI jobs validating and rebuilding the same bundle concurrently.

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/169af603d7fece3d. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/assets.py:158

    from .contract import validate_bundle

    if verify:
        binding = _verify_binding(value, base)
        root = Path(binding['path']).parent
    else:
        root = _path(value, base)
        binding = _fingerprint(root / 'receipt.json')
    validate_bundle(root)
    requests = {}
    for modality in sorted(MODALITIES):
        manifest = _load(root / 'manifests' / f'{modality}.json')
        for request in manifest['requests']:
            key = (modality, _text(request.get('request_id'), 'request_id'))
            if key in requests:
                raise ValueError('Ambiguous duplicate bundle request')
            requests[key] = request
    if binding != _fingerprint(root / 'receipt.json'):
        raise ValueError('Bundle changed during validation')
    return binding, requests


def _taste(asset: dict[str, Any], requests: dict[Any, Any], verify: bool) -> dict[str, Any]:
    if not requests:
        if any(key in asset for key in (*_TASTE_FIELDS, 'request_id')):
            raise ValueError('Taste claims require a validated bundle')
        return {}
    request_id = _text(asset.get('request_id'), 'bundle request_id')
    request = requests.get((asset['modality'], request_id))
    if request is None:
        raise ValueError('Asset request_id/modality does not match the bundle')
    result = dict(request_id=request_id, **{key: request[key] for key in _TASTE_FIELDS})
    if verify:
        if any(asset.get(key) != value for key, value in result.items()):
            raise ValueError('Asset taste lineage differs from its bundle request')
    elif any(key in asset for key in _TASTE_FIELDS):
        raise ValueError('Taste fields are derived from the bundle, not supplied')

View on GitHub (pinned to 8321021c54)