{"record":{"id":"e20073fd003a24a7","repo":"harry0703/MoneyPrinterTurbo","slug":"request-id-invalid-filename","errorCode":null,"errorMessage":"{request_id}: invalid filename","messagePattern":"(.+?): invalid filename","errorType":"http","errorClass":"HttpException","httpStatus":400,"severity":"error","filePath":"app/controllers/v1/video.py","lineNumber":70,"sourceCode":"if _enable_redis:\n    task_manager = RedisTaskManager(\n        max_concurrent_tasks=_max_concurrent_tasks,\n        redis_url=redis_url,\n        max_queued_tasks=_max_queued_tasks,\n    )\nelse:\n    task_manager = InMemoryTaskManager(\n        max_concurrent_tasks=_max_concurrent_tasks,\n        max_queued_tasks=_max_queued_tasks,\n    )\n\n\ndef _sanitize_upload_filename(filename: str, request_id: str) -> str:\n    # 浏览器或客户端有时会附带目录信息，甚至可能夹带 ../ 这类穿越片段。\n    # 这里只保留纯文件名，避免上传接口把文件写到目标目录之外。\n    normalized_name = (filename or \"\").replace(\"\\\\\", \"/\").split(\"/\")[-1].strip()\n    if not normalized_name or normalized_name in {\".\", \"..\"}:\n        raise HttpException(\n            task_id=request_id,\n            status_code=400,\n            message=f\"{request_id}: invalid filename\",\n        )\n    return normalized_name\n\n\ndef _resolve_path_within_directory(base_dir: str, unsafe_path: str, request_id: str) -> str:\n    try:\n        return file_security.resolve_path_within_directory(base_dir, unsafe_path)\n    except ValueError as exc:\n        logger.warning(\n            f\"reject unsafe file path, request_id: {request_id}, path: {unsafe_path}, \"\n            f\"error: {str(exc)}\"\n        )\n        raise HttpException(\n            task_id=request_id,\n            status_code=404 if str(exc) == \"file does not exist\" else 403,","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/harry0703/MoneyPrinterTurbo/blob/1f9f19c2021a68d04df228f33e9099a0c947f6f8/app/controllers/v1/video.py#L52-L88","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set an explicit, sane basename on the upload, e.g. os.path.basename(path) or Path(path).name on the client side.","Reject/repair filenames before upload: strip whitespace and refuse empty values.","If building multipart bodies manually, always include a filename= value in the Content-Disposition part."],"exampleFix":"# before\nfiles = {\"file\": (user_supplied_path_or_empty, fh)}\nrequests.post(url, files=files, headers=h)\n\n# after\nfrom pathlib import Path\nname = Path(user_supplied_path or \"\").name.strip()\nif not name or name in {\".\", \"..\"}:\n    raise ValueError(\"invalid upload filename\")\nfiles = {\"file\": (name, fh)}\nrequests.post(url, files=files, headers=h)","handlingStrategy":"validation","validationCode":"from pathlib import Path\nname = Path(filename or \"\").name.strip()\nif not name or name in {\".\", \"..\"}:\n    raise ValueError(\"upload filename is empty or a directory reference\")","typeGuard":"def is_safe_upload_filename(filename: str | None) -> bool:\n    n = (filename or \"\").replace(\"\\\\\", \"/\").split(\"/\")[-1].strip()\n    return bool(n) and n not in {\".\", \"..\"}","tryCatchPattern":"try:\n    resp = requests.post(url, files={\"file\": (name, fh)}, headers=h)\nexcept requests.HTTPError as e:\n    if e.response.status_code == 400 and \"invalid filename\" in e.response.text:\n        name = Path(name).name or \"upload.bin\"  # repair and let caller re-ask user\n    raise","preventionTips":["Always derive the upload name with os.path.basename/Path(...).name on the client.","Reject empty filenames in the UI before the request is built.","When constructing multipart bodies manually, always include filename= in Content-Disposition."],"tags":["upload","filename","path-traversal","http-400"],"backgroundTag":null,"analyzedSha":"1f9f19c2021a68d04df228f33e9099a0c947f6f8","analyzedAt":"2026-08-14T19:41:05.568Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}