affaan-m/ECC · error · ValueError

Provider provenance requires external_result origin

Error message

Provider provenance requires external_result origin

What it means

provider_provenance is only meaningful for assets whose origin is 'external_result'. The library throws this when an asset with a different origin supplies a non-null 'provider_provenance', since internal assets cannot claim an external provider's provenance.

Solutions

  1. Remove the 'provider_provenance' key from assets whose origin is not 'external_result'
  2. Or change the asset's origin to 'external_result' if it genuinely came from an external provider
  3. Audit the asset-producing pipeline so provenance is only attached when origin is external_result

Example fix

// before
{"id": "a1", "modality": "image", "origin": "internal", "provider_provenance": {"provider": "x"}}
// after
{"id": "a1", "modality": "image", "origin": "internal"}
Defensive patterns

Strategy: validation

Validate before calling

for a in assets:
    if a.get("origin") != "external_result" and a.get("provider_provenance") is not None:
        raise ValueError(f"asset {a['id']}: provider_provenance only allowed for external_result origin")

Type guard

def provenance_is_consistent(a: dict) -> bool:
    return a.get("origin") == "external_result" or a.get("provider_provenance") is None

Try / catch

try:
    ingest_assets(assets)
except ValueError as e:
    if "Provider provenance requires external_result" in str(e):
        strip_provenance_from_internal_assets(assets); retry()
    else:
        raise

Prevention

When it happens

Trigger: An asset with origin 'internal' (or any non-external_result value) that includes a 'provider_provenance' key set to a non-None value, passed to ingest_assets or validate_assets.

Common situations: Copy-pasting a template asset entry (including provider_provenance) and changing origin back to internal; a pipeline stamping provenance metadata onto all assets unconditionally.

Related errors


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

Appendix: source

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

    for asset in value:
        if not isinstance(asset, dict):
            raise ValueError('Each asset must be an object')
        asset_id = _text(asset.get('id'), 'asset id')
        if asset_id in ids:
            raise ValueError(f'Duplicate asset id: {asset_id}')
        ids.add(asset_id)
        if asset.get('modality') not in tuple(MODALITIES):
            raise ValueError('modality must be image, video or 3d_asset')
        if asset.get('origin') not in tuple(ORIGINS):
            raise ValueError('Invalid asset origin')
    return value


def _provenance(asset: dict[str, Any], base: Path, verify: bool) -> dict[str, Any] | None:
    source = asset.get('provider_provenance')
    if asset['origin'] != 'external_result':
        if source is not None:
            raise ValueError('Provider provenance requires external_result origin')
        return None
    if not isinstance(source, dict):
        raise ValueError('external_result requires provider provenance and local evidence')
    provider = _text(source.get('provider'), 'provider')
    identifiers = {key: _text(source[key], key) for key in ('request_id', 'workflow_id')
                   if key in source}
    if not identifiers:
        raise ValueError('Provider provenance requires request_id or workflow_id')
    if verify:
        evidence = _verify_binding(source.get('evidence'), base)
    else:
        evidence = _fingerprint(_path(source.get('evidence_path'), base))
    return dict(provider=provider, **identifiers, evidence=evidence,
                verification='supplied_local_evidence_only')


def _verify_binding(value: Any, base: Path, modality: str | None = None) -> dict[str, Any]:
    if not isinstance(value, dict):

View on GitHub (pinned to 8321021c54)