{"record":{"id":"ac7511c4204a0d4a","repo":"dgtlmoon/changedetection.io","slug":"asset-asset-name-not-found-ac7511","errorCode":null,"errorMessage":"Asset '{asset_name}' not found","messagePattern":"Asset '(.+?)' not found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"changedetectionio/blueprint/ui/preview.py","lineNumber":174,"sourceCode":"        # Get the processor type for this watch\n        processor_name = watch.get('processor', 'text_json_diff')\n\n        # Try to get the processor's preview module (works for both built-in and plugin processors)\n        from changedetectionio.processors import get_processor_submodule\n        processor_module = get_processor_submodule(processor_name, 'preview')\n\n        # Call the processor's get_asset() function\n        if processor_module and hasattr(processor_module, 'get_asset'):\n            result = processor_module.get_asset(\n                asset_name=asset_name,\n                watch=watch,\n                datastore=datastore,\n                request=request\n            )\n\n            if result is None:\n                from flask import abort\n                abort(404, description=f\"Asset '{asset_name}' not found\")\n\n            binary_data, content_type, cache_control = result\n\n            response = make_response(binary_data)\n            response.headers['Content-Type'] = content_type\n            if cache_control:\n                response.headers['Cache-Control'] = cache_control\n            return response\n        else:\n            logger.warning(f\"Processor {processor_name} does not implement get_asset()\")\n            from flask import abort\n            abort(404, description=f\"Processor '{processor_name}' does not support assets\")\n\n    return preview_blueprint\n","sourceCodeStart":156,"sourceCodeEnd":189,"githubUrl":"https://github.com/dgtlmoon/changedetection.io/blob/5d9c7c6da76340597243e8163c4f2439237fa0e8/changedetectionio/blueprint/ui/preview.py#L156-L189","documentation":"Same pattern as the diff asset endpoint, on the preview blueprint: the processor's get_asset() was called and returned None, so no asset with the requested name exists for this watch, and the handler aborts with 404 naming the missing asset.","triggerScenarios":"GET /preview/<uuid>/asset/<asset_name> before the asset was generated by a check, after the asset file was deleted/pruned, or with a misspelled/stale asset name.","commonSituations":"Loading a preview page right after watch creation (first check hasn't run); referencing an asset captured in an earlier snapshot version after data pruning.","solutions":["Run a check for the watch to (re)generate the asset","Use the asset name exposed by the current preview page/processor, not a cached one","Inspect watch.data_dir to confirm the expected asset file exists"],"exampleFix":"# before\nresp = requests.get(f'{base}/preview/{uuid}/asset/last-screenshot.png')\nresp.raise_for_status()\n\n# after\nresp = requests.get(f'{base}/preview/{uuid}/asset/last-screenshot.png')\nif resp.status_code == 404:\n    resp = regenerate_then_fetch(uuid)\nresp.raise_for_status()","handlingStrategy":"fallback","validationCode":"import os\ndef preview_asset_ready(watch, asset_name):\n    return os.path.isfile(os.path.join(watch.data_dir, asset_name))","typeGuard":null,"tryCatchPattern":"try:\n    r = requests.get(preview_asset_url)\n    r.raise_for_status()\nexcept requests.HTTPError as e:\n    if e.response.status_code == 404:\n        return PLACEHOLDER\n    raise","preventionTips":["Ensure a check has run and produced the asset","Prune UI references to deleted assets","Treat asset 404 as expected-state, not an error, in preview UIs"],"tags":["flask","asset","processor-plugin","http-404"],"backgroundTag":"http-404-not-found","analyzedSha":"5d9c7c6da76340597243e8163c4f2439237fa0e8","analyzedAt":"2026-08-27T19:41:16.067Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}