affaan-m/ECC · error · ValueError

Taste fields are derived from the bundle, not supplied

Error message

Taste fields are derived from the bundle, not supplied

What it means

In _taste with verify=False (ingest_assets path), an asset config supplied one of the derived taste fields (genre_number, genre_slug, style_fingerprint, reference_sha256) even though a bundle is present. Taste fields are derived exclusively from the bundle request; supplying them in the config is rejected so the bundle remains the single source of lineage truth. Only request_id may be supplied in the config.

Solutions

  1. Remove genre_number, genre_slug, style_fingerprint and reference_sha256 from the asset entry in the ingest config; keep only request_id.
  2. If you want those values, note they will be recomputed by ingest_assets from the bundle manifest request.
  3. Fix any config generator to emit only id, modality, origin, path, request_id (and optional provider_provenance) for bundle-bound assets.

Example fix

# before
{"id": "a1", "modality": "image", "origin": "local_passthrough", "request_id": "req-001", "genre_slug": "baroque"}
# after
{"id": "a1", "modality": "image", "origin": "local_passthrough", "request_id": "req-001"}
Defensive patterns

Strategy: validation

Validate before calling

TASTE_FIELDS = ('genre_number','genre_slug','style_fingerprint','reference_sha256')
assert not any(k in asset for k in TASTE_FIELDS), 'strip derived taste fields from config'

Prevention

When it happens

Trigger: Calling ingest_assets with an asset entry that includes any of genre_number/genre_slug/style_fingerprint/reference_sha256 while bundle_dir is configured; copying a validated receipt's asset record back into the ingest config (which contains the derived fields); a script merging bundle output into the config.

Common situations: Round-tripping a receipt back into a config by copy-paste; users 'filling in' what look like missing fields; auto-generated configs that dump full asset objects including derived lineage.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

        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)
                         if 'bundle_dir' in config else (None, {}))
    records = []
    for asset in _assets(config.get('assets')):
        record = {key: asset[key] for key in ('id', 'modality', 'origin')}
        record.update(_taste(asset, requests, False))
        record.update(_fingerprint(_path(asset.get('path'), base), asset['modality']))

View on GitHub (pinned to 8321021c54)