affaan-m/ECC · error · ValueError
Provider provenance requires request_id or workflow_id
Error message
Provider provenance requires request_id or workflow_id
What it means
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.
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
Example fix
// before
"provider_provenance": {"provider": "acme"}
// after
"provider_provenance": {"provider": "acme", "request_id": "req-123"} Defensive patterns
Strategy: validation
Validate before calling
for a in assets:
p = a.get("provider_provenance") or {}
if a.get("origin") == "external_result" and not (p.get("request_id") or p.get("workflow_id")):
raise ValueError(f"asset {a['id']}: provenance needs request_id or workflow_id") Type guard
def has_trace_id(p: dict | None) -> bool:
return bool(p) and bool(p.get("request_id") or p.get("workflow_id")) Try / catch
try:
ingest_assets(assets)
except ValueError as e:
if "requires request_id or workflow_id" in str(e):
backfill_ids_from_provider_logs(assets); retry()
else:
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- a generated candidate cannot claim original-source identity
- anchor evidence source duration is not bound to its receipt…
- artifact cites an unknown provenance source
- artifact has an unbound source duration
- artifact has invalid reference path
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/efed1bf0387c9aa7.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/assets.py:118
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):
raise ValueError('Missing artifact binding')
actual = _fingerprint(_path(value.get('path'), base), modality)
if type(value.get('bytes')) is not int or any(value.get(k) != v for k, v in actual.items()):
raise ValueError(f'Artifact changed or binding invalid: {actual["path"]}')
return actual
_TASTE_FIELDS = ('genre_number', 'genre_slug', 'style_fingerprint', 'reference_sha256')View on GitHub (pinned to 8321021c54)