{"record":{"id":"50bd2290ce7de25c","repo":"affaan-m/ECC","slug":"invalid-asset-origin","errorCode":null,"errorMessage":"Invalid asset origin","messagePattern":"Invalid asset origin","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":102,"sourceCode":"        raise ValueError('Expected a JSON object')\n    return data\n\n\ndef _assets(value: Any) -> list[dict[str, Any]]:\n    if not isinstance(value, list) or not value:\n        raise ValueError('assets must be a nonempty list')\n    ids = set()\n    for asset in value:\n        if not isinstance(asset, dict):\n            raise ValueError('Each asset must be an object')\n        asset_id = _text(asset.get('id'), 'asset id')\n        if asset_id in ids:\n            raise ValueError(f'Duplicate asset id: {asset_id}')\n        ids.add(asset_id)\n        if asset.get('modality') not in tuple(MODALITIES):\n            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)","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L84-L120","documentation":"Each asset must declare its origin from a fixed allowed set (ORIGINS). The library throws this when `asset.get('origin')` is absent or not in that tuple, because origin controls provenance rules (internal vs external_result) and provenance validation depends on it.","triggerScenarios":"ingest_assets or validate_assets called with an asset whose 'origin' key is missing, misspelled (e.g. 'external result', 'ExternalResult'), or uses a legacy origin name no longer in ORIGINS.","commonSituations":"Hand-edited asset manifests; manifests produced by an older tool version with different origin vocabulary; forgetting origin entirely when writing assets by hand; copying assets between projects with different origin schemes.","solutions":["Set 'origin' to a value in the ORIGINS tuple (check the ORIGINS constant in assets.py for the exact allowed strings)","Check the current ORIGINS definition if migrating from an older manifest — origin vocabulary may have changed","Inspect the offending asset entry to confirm the origin field exists and its exact value"],"exampleFix":"// before\n{\"id\": \"a1\", \"modality\": \"image\", \"origin\": \"generated\"}\n// after\n{\"id\": \"a1\", \"modality\": \"image\", \"origin\": \"internal\"}","handlingStrategy":"validation","validationCode":"ORIGINS = frozenset(load_origins_from_library())\nfor a in assets:\n    if a.get(\"origin\") not in ORIGINS:\n        raise ValueError(f\"asset {a.get('id')}: invalid origin {a.get('origin')!r}\")","typeGuard":"def has_valid_origin(a: dict) -> bool:\n    return a.get(\"origin\") in KNOWN_ORIGINS","tryCatchPattern":"try:\n    ingest_assets(assets)\nexcept ValueError as e:\n    if str(e) == \"Invalid asset origin\":\n        log.error(\"check 'origin' values against ORIGINS in assets.py\"); revalidate_after_fix()\n    else:\n        raise","preventionTips":["Import ORIGINS from the library instead of hardcoding origin strings","Keep manifests generated by tooling, not hand-edited","Add enum validation to your manifest CI checks"],"tags":["validation","assets","origin"],"backgroundTag":"invalid-enum-value","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"}