{"record":{"id":"e05aa3bf8b7195f7","repo":"harry0703/MoneyPrinterTurbo","slug":"request-id-requested-range-is-not-satisfiable","errorCode":null,"errorMessage":"{request_id}: requested range is not satisfiable","messagePattern":"(.+?): requested range is not satisfiable","errorType":"http","errorClass":"HttpException","httpStatus":416,"severity":"error","filePath":"app/controllers/v1/video.py","lineNumber":130,"sourceCode":"        logger.warning(\n            f\"skip unsafe task output path, request_id: {request_id}, path: {file}, \"\n            f\"error: {str(exc)}\"\n        )\n        return file\n\n    relative_path = os.path.relpath(resolved_path, task_dir).replace(\"\\\\\", \"/\")\n    uri_path = f\"tasks/{relative_path}\"\n    if endpoint:\n        return f\"{endpoint.rstrip('/')}/{uri_path}\"\n    return f\"/{uri_path}\"\n\n\ndef _parse_byte_range(\n    range_header: str | None, file_size: int, request_id: str\n) -> tuple[int, int]:\n    \"\"\"解析单段 HTTP Range，并把无效或越界请求稳定转换成 416。\"\"\"\n    if file_size <= 0:\n        raise HttpException(\n            task_id=request_id,\n            status_code=416,\n            message=f\"{request_id}: requested range is not satisfiable\",\n        )\n\n    if not range_header:\n        return 0, file_size - 1\n\n    try:\n        # 视频播放器这里只需要单段 bytes range。拒绝多段请求可以避免返回体\n        # 与 Content-Range 不一致，也避免异常字符串落入 int() 产生 500。\n        if not range_header.startswith(\"bytes=\") or \",\" in range_header:\n            raise ValueError(\"unsupported range format\")\n        start_text, end_text = range_header[6:].split(\"-\", 1)\n        if not start_text and not end_text:\n            raise ValueError(\"empty range\")\n\n        if not start_text:","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/harry0703/MoneyPrinterTurbo/blob/1f9f19c2021a68d04df228f33e9099a0c947f6f8/app/controllers/v1/video.py#L112-L148","documentation":"Raised by _parse_byte_range in app/controllers/v1/video.py (first branch) when the file being streamed has size <= 0. Even without a Range header the function refuses, because there is no satisfiable byte range for an empty (or zero-length) file and video playback would be undefined. Maps to HTTP 416.","triggerScenarios":"GET /api/v1/stream/<path> (with or without a Range header) where the resolved on-disk file is 0 bytes; a generation task produced an empty/partial output file; a file truncated externally after task completion.","commonSituations":"Upstream video generation silently wrote an empty file; disk-full during write; task marked complete before the artifact was flushed; deleting/truncating artifacts out from under a running server.","solutions":["Verify the task actually finished successfully and re-check the artifact path returned by GET /tasks/{id}; regenerate if the output is empty.","On the server, inspect the file with ls -l / os.path.getsize to confirm it is 0 bytes, then re-run generation.","Guard clients: treat 416 on a stream as a corrupt-artifact signal, not a range negotiation problem."],"exampleFix":"# before\nresp = requests.get(stream_url, headers={\"Range\": \"bytes=0-1023\"})\nassert resp.status_code == 206\n\n# after\nsize = os.path.getsize(local_artifact) if local_artifact else None\nif size is None or size <= 0:\n    task = requests.get(f\"{base}/api/v1/tasks/{task_id}\", headers=h).json()\n    stream_url = task[\"data\"][\"videos\"][0]  # fresh artifact\nresp = requests.get(stream_url, headers={\"Range\": \"bytes=0-1023\"})","handlingStrategy":"validation","validationCode":"size = os.path.getsize(video_path)  # or Content-Length from a plain GET\nif size <= 0:\n    raise ValueError(\"artifact is empty; regenerate the video\")","typeGuard":"def has_satisfiable_range(file_size: int) -> bool:\n    return isinstance(file_size, int) and file_size > 0","tryCatchPattern":"resp = requests.get(url, headers={\"Range\": \"bytes=0-1023\"})\nif resp.status_code == 416:\n    # empty or corrupt artifact; re-fetch task and regenerate, don't re-negotiate ranges\n    task = get_task(task_id); url = task[\"videos\"][0]","preventionTips":["Check Content-Length > 0 before a player attaches a Range request.","Treat 416 on the first range request as a corrupt-artifact signal.","Verify generation tasks report success before exposing stream URIs to players."],"tags":["http-range","streaming","http-416","empty-file"],"backgroundTag":null,"analyzedSha":"1f9f19c2021a68d04df228f33e9099a0c947f6f8","analyzedAt":"2026-08-14T19:41:05.568Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}