{"record":{"id":"32283e2e1fb9355e","repo":"affaan-m/ECC","slug":"asset-must-be-a-local-regular-file","errorCode":null,"errorMessage":"asset must be a local regular file","messagePattern":"asset must be a local regular file","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/resolve.py","lineNumber":115,"sourceCode":"    for event in placements:\n        identifier = event.get(\"id\")\n        if not isinstance(identifier, str) or not identifier or identifier in seen:\n            raise ValueError(\"placement id must be unique and nonempty\")\n        seen.add(identifier)\n        start = _integer(event.get(\"record_frame\"), \"record_frame\")\n        frames = _integer(event.get(\"frames\"), \"frames\", 1)\n        opacity = event.get(\"opacity\")\n        if (\n            isinstance(opacity, bool)\n            or not isinstance(opacity, (int, float))\n            or not math.isfinite(opacity)\n            or not 0 <= opacity <= 100\n        ):\n            raise ValueError(\"explicit opacity must be finite within 0..100\")\n        composite = _integer(event.get(\"composite\"), \"composite\")\n        raw_asset = event.get(\"asset\")\n        if not isinstance(raw_asset, (str, Path)) or not str(raw_asset):\n            raise ValueError(\"asset must be a local regular file\")\n        asset = Path(raw_asset).expanduser().resolve()\n        if not asset.is_file():\n            raise ValueError(f\"asset must be a local regular file: {asset}\")\n        alpha = event.get(\"requires_alpha\", False)\n        if not isinstance(alpha, bool):\n            raise ValueError(\"requires_alpha must be boolean\")\n        key = str(asset)\n        if key not in metadata:\n            metadata[key] = probe(asset)\n        info = metadata[key]\n        if _fps(info.get(\"fps\")) != rate:\n            raise ValueError(f\"asset fps differs from timeline: {asset}\")\n        if _integer(info.get(\"frames\"), \"asset frames\", 1) < frames:\n            raise ValueError(f\"asset contains too few frames: {asset}\")\n        if alpha and info.get(\"has_alpha\") is not True:\n            raise ValueError(f\"asset requires verified alpha: {asset}\")\n        checked.append(\n            {","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/resolve.py#L97-L133","documentation":"allocate_placements requires each event's 'asset' to be a str or pathlib.Path whose string form is nonempty; otherwise it raises ValueError('asset must be a local regular file'). This generic message fires on missing/empty/wrong-typed asset values, before the path is even resolved.","triggerScenarios":"An event dict missing 'asset', asset=None, asset='' , or asset being something else entirely (an int id, a URL string is actually accepted as a str here but will fail the next is_file() check — the type failure raises this one).","commonSituations":"Templated configs where a placeholder wasn't filled in; renamed key ('file' instead of 'asset'); passing a remote URL expecting the library to download it (it requires local files); passing a directory instead of a file path (type ok, but see the path-specific variant).","solutions":["Ensure every event has 'asset' set to a nonempty string or pathlib.Path pointing to a local file","Fix key typos so the path lands under 'asset'","Download remote assets to disk first; this API works only with local files","Pre-validate event dicts with a schema (e.g. pydantic/zod-like check: asset: str, min_length 1) before calling"],"exampleFix":"// before\n{\"id\": \"bug\", \"asset\": \"\"}\n// after\n{\"id\": \"bug\", \"asset\": \"/assets/ladybug.webm\"}","handlingStrategy":"validation","validationCode":"def validate_assets(events):\n    for ev in events:\n        a = ev.get('asset')\n        if not isinstance(a, (str, __import__('pathlib').Path)) or not str(a):\n            raise ValueError(f'placement {ev.get(\"id\")!r} has no asset path')\n\nvalidate_assets(placements)","typeGuard":"from pathlib import Path\n\ndef has_asset(ev) -> bool:\n    a = ev.get('asset')\n    return isinstance(a, (str, Path)) and bool(str(a))","tryCatchPattern":"try:\n    resolve.plan(placements, fps=fps)\nexcept ValueError as e:\n    if 'asset must be a local regular file' in str(e):\n        raise PlacementError('a placement is missing its asset field') from e\n    raise","preventionTips":["Validate placement dicts against a schema before calling","Fill placeholders in templated configs before rendering","Download remote assets to local files first"],"tags":["validation","asset","placements"],"backgroundTag":"empty-required-field","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"}