harry0703/MoneyPrinterTurbo · error · HttpException

: invalid filename

Error message

{request_id}: invalid filename

What it means

Raised by _sanitize_upload_filename in app/controllers/v1/video.py when an uploaded file's name, after stripping any directory components (both / and \ separators), is empty or is exactly '.' or '..'. The sanitization exists because browsers and clients sometimes attach directory information or ../ traversal fragments, and this guard keeps uploads inside the target directory. It maps to HTTP 400 with '{request_id}: invalid filename'.

Solutions

  1. Set an explicit, sane basename on the upload, e.g. os.path.basename(path) or Path(path).name on the client side.
  2. Reject/repair filenames before upload: strip whitespace and refuse empty values.
  3. If building multipart bodies manually, always include a filename= value in the Content-Disposition part.

Example fix

# before
files = {"file": (user_supplied_path_or_empty, fh)}
requests.post(url, files=files, headers=h)

# after
from pathlib import Path
name = Path(user_supplied_path or "").name.strip()
if not name or name in {".", ".."}:
    raise ValueError("invalid upload filename")
files = {"file": (name, fh)}
requests.post(url, files=files, headers=h)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
name = Path(filename or "").name.strip()
if not name or name in {".", ".."}:
    raise ValueError("upload filename is empty or a directory reference")

Type guard

def is_safe_upload_filename(filename: str | None) -> bool:
    n = (filename or "").replace("\\", "/").split("/")[-1].strip()
    return bool(n) and n not in {".", ".."}

Try / catch

try:
    resp = requests.post(url, files={"file": (name, fh)}, headers=h)
except requests.HTTPError as e:
    if e.response.status_code == 400 and "invalid filename" in e.response.text:
        name = Path(name).name or "upload.bin"  # repair and let caller re-ask user
    raise

Prevention

When it happens

Trigger: Uploading a file whose filename is an empty string, '/', '.', '..', or only whitespace/backslashes; a multipart form built by hand that omits the filename parameter; a client sending a full Windows path that reduces to '..' after splitting.

Common situations: Programmatic uploads where the client passes a path variable instead of a basename; tests using placeholder filenames like '.'; HTTP libraries that default filename to '' when given None.

Related errors


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

Appendix: source

Thrown at app/controllers/v1/video.py:70

if _enable_redis:
    task_manager = RedisTaskManager(
        max_concurrent_tasks=_max_concurrent_tasks,
        redis_url=redis_url,
        max_queued_tasks=_max_queued_tasks,
    )
else:
    task_manager = InMemoryTaskManager(
        max_concurrent_tasks=_max_concurrent_tasks,
        max_queued_tasks=_max_queued_tasks,
    )


def _sanitize_upload_filename(filename: str, request_id: str) -> str:
    # 浏览器或客户端有时会附带目录信息,甚至可能夹带 ../ 这类穿越片段。
    # 这里只保留纯文件名,避免上传接口把文件写到目标目录之外。
    normalized_name = (filename or "").replace("\\", "/").split("/")[-1].strip()
    if not normalized_name or normalized_name in {".", ".."}:
        raise HttpException(
            task_id=request_id,
            status_code=400,
            message=f"{request_id}: invalid filename",
        )
    return normalized_name


def _resolve_path_within_directory(base_dir: str, unsafe_path: str, request_id: str) -> str:
    try:
        return file_security.resolve_path_within_directory(base_dir, unsafe_path)
    except ValueError as exc:
        logger.warning(
            f"reject unsafe file path, request_id: {request_id}, path: {unsafe_path}, "
            f"error: {str(exc)}"
        )
        raise HttpException(
            task_id=request_id,
            status_code=404 if str(exc) == "file does not exist" else 403,

View on GitHub (pinned to 1f9f19c202)