harry0703/MoneyPrinterTurbo · error · ValueError

unsupported local material type {extension or '<none>'}: {ma

Error message

unsupported local material type {extension or '<none>'}: {material.url}; allowed extensions: {allowed}

What it means

Thrown while validating --video-materials for local video source tasks. Each material URL is first resolved via _resolve_cli_file (against the local_videos storage dir), then its lowercase extension is checked against local_material_extensions, which is const.FILE_TYPE_VIDEOS + const.FILE_TYPE_IMAGES plus .avi and .flv (cli.py:658-663). Any extension outside that set — including no extension at all ('<none>') — aborts the run. Validation happens for all materials before any copy, so no orphan files are left behind.

Source

Thrown at cli.py:730

            raise ValueError("subtitle font must use the .ttf or .ttc extension")
        # 下游根据 resource/fonts 内的文件名拼接路径,因此仍保留纯文件名。
        params.font_name = os.path.basename(font_path)

    if params.video_source != "local" or stop_at not in {"materials", "video"}:
        return

    local_videos_dir = utils.storage_dir("local_videos", create=True)
    resolved_materials: list[tuple[MaterialInfo, str, str]] = []
    for material in params.video_materials or []:
        source_path = _resolve_cli_file(
            material.url,
            description="local material",
            fallback_dir=local_videos_dir,
        )
        extension = os.path.splitext(source_path)[1].lower()
        if extension not in local_material_extensions:
            allowed = ", ".join(sorted(local_material_extensions))
            raise ValueError(
                f"unsupported local material type {extension or '<none>'}: "
                f"{material.url}; allowed extensions: {allowed}"
            )
        resolved_materials.append((material, source_path, extension))

    # 所有输入检查通过后再复制,避免第二个文件无效时留下第一个文件的
    # 孤儿副本。
    prepared_paths: dict[str, str] = {}
    for material, source_path, extension in resolved_materials:
        prepared_path = prepared_paths.get(source_path)
        if prepared_path is None:
            if _path_is_within_directory(source_path, local_videos_dir):
                prepared_path = source_path
            else:
                prepared_path = os.path.join(
                    local_videos_dir,
                    f"cli-material-{uuid4().hex}{extension}",
                )

View on GitHub (pinned to 1f9f19c202)

Solutions

  1. Convert the offending material to a supported format (mp4/webm/jpg/png etc., or avi/flv) with ffmpeg before passing it
  2. Fix the filename so it has the correct supported extension — check the exact allowed list printed in the error message
  3. Add the extension to const.FILE_TYPE_VIDEOS or const.FILE_TYPE_IMAGES in app/constants if the format is genuinely supported downstream, then rerun (cli.py builds the allowed set from those constants)

Example fix

# before
--video-source local --stop-at video \
  --video-material clip.mkv

# after
ffmpeg -i clip.mkv -c:v libx264 -c:a aac clip.mp4
--video-source local --stop-at video \
  --video-material clip.mp4
Defensive patterns

Strategy: validation

Validate before calling

import os
from app import const

def build_local_material_extensions() -> set[str]:
    return {
        *(f".{e}" for e in const.FILE_TYPE_VIDEOS),
        *(f".{e}" for e in const.FILE_TYPE_IMAGES),
        ".avi",
        ".flv",
    }

def materials_are_valid(paths: list[str]) -> bool:
    allowed = build_local_material_extensions()
    return all(os.path.splitext(p)[1].lower() in allowed for p in paths)

Type guard

def is_supported_material(path: str) -> bool:
    """Guard: material path has an extension in the local-material allowlist."""
    return isinstance(path, str) and os.path.splitext(path)[1].lower() in build_local_material_extensions()

Prevention

When it happens

Trigger: CLI run with --video-source local, stop_at in {materials, video}, and a --video-material entry whose resolved path ends in an unsupported extension (e.g. .gifv, .webp if not in const lists, .mkv if excluded, .txt) or has no extension; also triggered by directories or misresolved relative paths.

Common situations: Mixing in an unsupported format like .mkv/.wmv/.bmp that const.FILE_TYPE_* does not include; a material filename missing its extension after download; passing a URL-style string that _resolve_cli_file resolves to something unexpected; Windows-hidden double extensions.

Related errors


AI-assisted analysis of harry0703/MoneyPrinterTurbo@1f9f19c202 (2026-08-14). Data as JSON: /api/errors/8a635efcf4a62623. Report an issue: GitHub.