harry0703/MoneyPrinterTurbo · error · ValueError

background music must be a supported audio file inside stora

Error message

background music must be a supported audio file inside storage/bgm or resource/songs ({supported_extensions}): {params.bgm_file}

What it means

Thrown by the CLI parameter validator when --bgm-type=custom but --bgm-file cannot be resolved by bgm_service.resolve_bgm_file. That service (app/services/bgm.py:303) only accepts audio files whose extension is in SUPPORTED_BGM_EXTENSIONS (.mp3, .m4a, .aac, .wav, .flac, .ogg, .opus, .wma) AND whose path resolves safely inside the user upload directory (storage/bgm) or the built-in song directory (resource/songs). Any other extension, a path-traversal attempt, or a nonexistent file raises ValueError upstream, which the CLI re-raises with this consolidated message.

Source

Thrown at cli.py:699

            # CLI 为一个不会被读取的文件执行路径解析、存在性检查或格式
            # 校验。
            params.bgm_file = ""
        elif not params.bgm_file:
            # 缺少文件是否构成错误取决于通用 BGM 开关,不能在 argparse 阶段
            # 无条件拦截,否则 ``custom + 0%`` 会和 WebUI、服务层行为不一致。
            raise ValueError("--bgm-file is required when --bgm-type is custom")
        else:
            try:
                # CLI、WebUI 和任务服务必须共用同一个 BGM 文件边界。这里直接
                # 复用服务层解析,既支持用户上传目录和内置歌曲目录,也
                # 自动继承新增音频格式及路径安全规则,避免多个入口分别
                # 维护白名单。
                params.bgm_file = bgm_service.resolve_bgm_file(params.bgm_file)
            except ValueError as exc:
                supported_extensions = ", ".join(
                    bgm_service.SUPPORTED_BGM_EXTENSIONS
                )
                raise ValueError(
                    "background music must be a supported audio file inside "
                    f"storage/bgm or resource/songs ({supported_extensions}): "
                    f"{params.bgm_file}"
                ) from exc

    if params.subtitle_enabled and params.font_name and stop_at == "video":
        font_path = _resolve_managed_resource_file(
            params.font_name,
            resource_dir=utils.font_dir(),
            description="subtitle font",
        )
        if not font_path.lower().endswith((".ttf", ".ttc")):
            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

View on GitHub (pinned to 1f9f19c202)

Solutions

  1. Check the extension is one of: .mp3, .m4a, .aac, .wav, .flac, .ogg, .opus, .wma — convert the file (e.g. with ffmpeg -i in.mp4 out.mp3) if it is a different container
  2. Copy the audio file into storage/bgm/ (user uploads) or resource/songs/ (built-in songs), then pass just the filename or a path inside those directories
  3. Verify the file actually exists: ls storage/bgm resource/songs — a nonexistent file fails resolution even with a valid extension
  4. If you need a new audio format supported, add the extension to SUPPORTED_BGM_EXTENSIONS in app/services/bgm.py:28 (CLI, WebUI and task service all inherit it automatically)

Example fix

# before
--bgm-type custom --bgm-file /home/user/Music/track.mp4

# after (convert, then place inside the allowed directory)
ffmpeg -i /home/user/Music/track.mp4 /tmp/track.mp3
cp /tmp/track.mp3 storage/bgm/track.mp3
--bgm-type custom --bgm-file track.mp3
Defensive patterns

Strategy: validation

Validate before calling

from app.services import bgm as bgm_service
from pathlib import Path

def bgm_file_is_valid(path: str) -> bool:
    if not path or Path(path).suffix.lower() not in bgm_service.SUPPORTED_BGM_EXTENSIONS:
        return False
    try:
        bgm_service.resolve_bgm_file(path)
        return True
    except ValueError:
        return False

# before running the task:
if params.bgm_type == "custom" and not bgm_file_is_valid(params.bgm_file):
    print("BGM file missing, unsupported extension, or outside storage/bgm and resource/songs")

Type guard

def is_supported_bgm_path(path: str) -> bool:
    """Type/value guard: non-empty str with a whitelisted audio extension."""
    return (
        isinstance(path, str)
        and bool(path.strip())
        and Path(path).suffix.lower() in bgm_service.SUPPORTED_BGM_EXTENSIONS
    )

Try / catch

try:
    params.bgm_file = bgm_service.resolve_bgm_file(params.bgm_file)
except ValueError as exc:
    # exc from the service layer already states whether it is an extension,
    # existence, or path-traversal failure; log and fail fast.
    logger.error("invalid bgm file %r: %s", params.bgm_file, exc)
    raise

Prevention

When it happens

Trigger: Running the CLI with --bgm-type custom --bgm-file <path> where: (1) the extension is not one of the eight supported audio extensions (e.g. .mp4, .txt, or no extension); (2) the file does not exist in either storage/bgm or resource/songs; (3) the path tries to escape those directories (e.g. ../secrets.mp3) and is rejected by file_security.resolve_path_within_directory.

Common situations: Passing a full absolute path from elsewhere on disk (outside the two whitelisted dirs); uploading an MP4 or video container thinking it works as BGM; typo'd filename; file was deleted or never copied into storage/bgm; script generated the name with a missing extension.

Related errors


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