affaan-m/ECC · error · ValueError

Asset request_id/modality does not match the bundle

Error message

Asset request_id/modality does not match the bundle

What it means

During _taste (called by ingest_assets and validate_assets), an asset declares a bundle request_id, but the (modality, request_id) pair is not found among the requests loaded from the validated taste bundle's manifests. The library refuses to attach taste lineage (genre_number, genre_slug, style_fingerprint, reference_sha256) to an asset whose request does not exist in the bundle for that modality. This prevents silently pairing an asset with taste fields that belong to a different request.

Solutions

  1. Print the bundle manifests and confirm the exact (modality, request_id) pair exists: for each modality in image/video/3d_asset, read <bundle_dir>/manifests/<modality>.json and check the requests[].request_id values.
  2. Fix the asset's request_id in the ingest config to match a request under the same modality.
  3. If the modality of the asset changed, move the request id lookup to the correct modality's manifest or regenerate the bundle request for that modality.
  4. If the bundle was regenerated, update all configs to the new request ids (or re-run the bundle generation step and rewire).

Example fix

# before (config)
{"assets": [{"id": "a1", "modality": "video", "origin": "local_passthrough", "request_id": "req-001"}]}
# after (request req-001 lives under image, asset is video; use the video request id)
{"assets": [{"id": "a1", "modality": "video", "origin": "local_passthrough", "request_id": "req-002"}]}
Defensive patterns

Strategy: validation

Validate before calling

import json, pathlib
def request_in_bundle(bundle_dir, modality, request_id):
    manifest = json.loads(pathlib.Path(bundle_dir, 'manifests', f'{modality}.json').read_text())
    return any(r.get('request_id') == request_id for r in manifest['requests'])
# assert request_in_bundle(cfg['bundle_dir'], asset['modality'], asset['request_id'])

Type guard

def has_bundle_request(asset, requests):
    rid = asset.get('request_id')
    return isinstance(rid, str) and (asset.get('modality'), rid) in requests

Prevention

When it happens

Trigger: Calling ingest_assets with an asset whose request_id does not exist in bundle manifests, or whose modality key (image/video/3d_asset) differs from the modality the request was filed under; calling validate_assets on a receipt containing such a mismatched (request_id, modality) combination. Also triggered by a bundle with manifests regenerated/renamed request ids after the config was written.

Common situations: Copy-pasting request ids between configs; regenerating a taste bundle (new random request ids) without updating asset configs; changing an asset's modality field without updating the request id; typos in request_id strings; referencing a request that lives under a different modality manifest.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/c462a888ffd9fc96. Report an issue: GitHub.

Appendix: source

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

        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')
    return result


def ingest_assets(config_path: str | Path, out_receipt: str | Path) -> dict[str, Any]:
    """Bind local assets/provenance/lineage; write a new receipt, never overwrite."""
    config_file = _path(config_path, Path.cwd())
    config = _load(config_file)
    base = config_file.parent
    output = _path(out_receipt, Path.cwd())
    if output.exists():
        raise ValueError(f'Receipt output already exists: {output}')
    binding, requests = (_bundle(config['bundle_dir'], base, False)

View on GitHub (pinned to 8321021c54)