{"record":{"id":"efed1bf0387c9aa7","repo":"affaan-m/ECC","slug":"provider-provenance-requires-request-id-or-workflow-id","errorCode":null,"errorMessage":"Provider provenance requires request_id or workflow_id","messagePattern":"Provider provenance requires request_id or workflow_id","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":118,"sourceCode":"            raise ValueError('modality must be image, video or 3d_asset')\n        if asset.get('origin') not in tuple(ORIGINS):\n            raise ValueError('Invalid asset origin')\n    return value\n\n\ndef _provenance(asset: dict[str, Any], base: Path, verify: bool) -> dict[str, Any] | None:\n    source = asset.get('provider_provenance')\n    if asset['origin'] != 'external_result':\n        if source is not None:\n            raise ValueError('Provider provenance requires external_result origin')\n        return None\n    if not isinstance(source, dict):\n        raise ValueError('external_result requires provider provenance and local evidence')\n    provider = _text(source.get('provider'), 'provider')\n    identifiers = {key: _text(source[key], key) for key in ('request_id', 'workflow_id')\n                   if key in source}\n    if not identifiers:\n        raise ValueError('Provider provenance requires request_id or workflow_id')\n    if verify:\n        evidence = _verify_binding(source.get('evidence'), base)\n    else:\n        evidence = _fingerprint(_path(source.get('evidence_path'), base))\n    return dict(provider=provider, **identifiers, evidence=evidence,\n                verification='supplied_local_evidence_only')\n\n\ndef _verify_binding(value: Any, base: Path, modality: str | None = None) -> dict[str, Any]:\n    if not isinstance(value, dict):\n        raise ValueError('Missing artifact binding')\n    actual = _fingerprint(_path(value.get('path'), base), modality)\n    if type(value.get('bytes')) is not int or any(value.get(k) != v for k, v in actual.items()):\n        raise ValueError(f'Artifact changed or binding invalid: {actual[\"path\"]}')\n    return actual\n\n\n_TASTE_FIELDS = ('genre_number', 'genre_slug', 'style_fingerprint', 'reference_sha256')","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L100-L136","documentation":"A provider_provenance block must contain at least one traceable identifier: request_id or workflow_id. The library throws this when neither key is present (or both fail _text validation), because provenance without an identifier cannot be correlated with the provider.","triggerScenarios":"provider_provenance dict supplied with only a 'provider' name and no request_id/workflow_id; keys present but with empty/whitespace values rejected by _text, leaving identifiers empty.","commonSituations":"Recording only the vendor name when logging external generations; losing the request id because the caller didn't persist the provider API response; empty-string ids from template placeholders.","solutions":["Add 'request_id' (or 'workflow_id') from the provider API response to the provider_provenance dict","Ensure the identifier value is a non-empty string, not empty or whitespace","Persist the provider response's ids at call time so they are available when building the manifest"],"exampleFix":"// before\n\"provider_provenance\": {\"provider\": \"acme\"}\n// after\n\"provider_provenance\": {\"provider\": \"acme\", \"request_id\": \"req-123\"}","handlingStrategy":"validation","validationCode":"for a in assets:\n    p = a.get(\"provider_provenance\") or {}\n    if a.get(\"origin\") == \"external_result\" and not (p.get(\"request_id\") or p.get(\"workflow_id\")):\n        raise ValueError(f\"asset {a['id']}: provenance needs request_id or workflow_id\")","typeGuard":"def has_trace_id(p: dict | None) -> bool:\n    return bool(p) and bool(p.get(\"request_id\") or p.get(\"workflow_id\"))","tryCatchPattern":"try:\n    ingest_assets(assets)\nexcept ValueError as e:\n    if \"requires request_id or workflow_id\" in str(e):\n        backfill_ids_from_provider_logs(assets); retry()\n    else:\n        raise","preventionTips":["Capture request_id/workflow_id from the provider response immediately at call time","Store ids as non-empty trimmed strings","Add a CI check that every external_result provenance contains a trace id"],"tags":["provenance","validation","traceability"],"backgroundTag":"missing-required-argument","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}