dgtlmoon/changedetection.io · error

Processor '{processor_name}' does not support assets

Error message

Processor '{processor_name}' does not support assets

What it means

abort(404) raised when the processor serving /diff/<uuid>/asset/... does not implement the get_asset() hook at all. The endpoint checks hasattr(processor_module, 'get_asset'); text-based processors typically don't provide binary assets, so any asset request against them 404s with this description and a server-side warning log.

Source

Thrown at changedetectionio/blueprint/ui/diff.py:626

                datastore=datastore,
                request=request
            )

            if result is None:
                from flask import abort
                abort(404, description=f"Asset '{asset_name}' not found")

            binary_data, content_type, cache_control = result

            response = make_response(binary_data)
            response.headers['Content-Type'] = content_type
            if cache_control:
                response.headers['Cache-Control'] = cache_control
            return response
        else:
            logger.warning(f"Processor {processor_name} does not implement get_asset()")
            from flask import abort
            abort(404, description=f"Processor '{processor_name}' does not support assets")

    return diff_blueprint

View on GitHub (pinned to 5d9c7c6da7)

Solutions

  1. Only request assets from processors that implement get_asset (e.g. visual/screenshot-capable ones)
  2. Enable the screenshot/visual mode for the watch if you need screenshot assets
  3. For custom processors, implement get_asset(watch, datastore, request, asset_name) returning (binary_data, content_type, cache_control) or None

Example fix

# before (custom processor lacking the hook)
# requests.get(f'{base}/diff/{uuid}/asset/screenshot.png') -> 404

# after
def get_asset(watch, datastore, request, asset_name):
    p = os.path.join(watch.data_dir, asset_name)
    if not os.path.isfile(p):
        return None
    return open(p,'rb').read(), 'image/png', 'max-age=60'
Defensive patterns

Strategy: type-guard

Validate before calling

from changedetectionio.processors import get_processor_submodule
def processor_serves_assets(name):
    m = get_processor_submodule(name, 'difference') or get_processor_submodule(name, None)
    return m is not None and hasattr(m, 'get_asset')

Type guard

def has_get_asset(processor_module) -> bool:
    """True when the processor can serve binary assets."""
    return callable(getattr(processor_module, 'get_asset', None))

Try / catch

if not hasattr(processor_module, 'get_asset'):
    logger.warning(f"Processor {processor_name} does not implement get_asset()")
    abort(404, description=f"Processor '{processor_name}' does not support assets")

Prevention

When it happens

Trigger: GET /diff/<uuid>/asset/<name> for a watch whose processor module has no get_asset function; also when the processor name resolves to a module without the hook (lookup returns a module but the attribute check fails).

Common situations: UI or scripts assuming all processors serve screenshots; custom processors that never implemented get_asset; after changing a watch's processor type, stale links still point at the asset route.

Related errors


AI-assisted analysis of dgtlmoon/changedetection.io@5d9c7c6da7 (2026-08-27). Data as JSON: /api/errors/56ea1345db758f05. Report an issue: GitHub.