harry0703/MoneyPrinterTurbo · error · HttpException

{request_id}: 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'.

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)

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.