{"record":{"id":"058451e170f4cf4a","repo":"harry0703/MoneyPrinterTurbo","slug":"failed-to-generate-sonilo-video-proxy-detail","errorCode":null,"errorMessage":"failed to generate Sonilo video proxy: {detail}","messagePattern":"failed to generate Sonilo video proxy: (.+?)","errorType":"exception","errorClass":"SoniloError","httpStatus":null,"severity":"error","filePath":"app/services/sonilo.py","lineNumber":192,"sourceCode":"    ]\n    try:\n        result = subprocess.run(\n            command,\n            capture_output=True,\n            text=True,\n            timeout=600,\n            check=False,\n        )\n    except subprocess.TimeoutExpired as exc:\n        _remove_file(proxy_path)\n        raise SoniloError(\"Sonilo video proxy generation timed out\") from exc\n    except OSError as exc:\n        _remove_file(proxy_path)\n        raise SoniloError(\"failed to run FFmpeg for Sonilo video proxy\") from exc\n    if result.returncode != 0:\n        _remove_file(proxy_path)\n        detail = (result.stderr or \"\").strip().replace(\"\\n\", \" \")[-500:]\n        raise SoniloError(f\"failed to generate Sonilo video proxy: {detail}\")\n    proxy_size = os.path.getsize(proxy_path) if os.path.isfile(proxy_path) else 0\n    if proxy_size <= 0 or proxy_size > MAX_PROXY_BYTES:\n        _remove_file(proxy_path)\n        raise SoniloError(\"Sonilo video proxy is empty or exceeds the 300 MB limit\")\n    logger.info(\n        f\"Sonilo video proxy prepared: source={video_path}, size={proxy_size} bytes\"\n    )\n    return proxy_path\n\n\ndef _parse_event(raw_line: bytes) -> dict[str, Any]:\n    \"\"\"严格解析单条 NDJSON，禁止静默忽略截断或非对象响应。\"\"\"\n    try:\n        event = json.loads(raw_line.decode(\"utf-8\"))\n    except (UnicodeDecodeError, json.JSONDecodeError) as exc:\n        raise SoniloError(\"Sonilo returned malformed streaming data\") from exc\n    if not isinstance(event, dict) or not isinstance(event.get(\"type\"), str):\n        raise SoniloError(\"Sonilo returned an invalid streaming event\")","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/harry0703/MoneyPrinterTurbo/blob/1f9f19c2021a68d04df228f33e9099a0c947f6f8/app/services/sonilo.py#L174-L210","documentation":"Raised when the FFmpeg proxy-generation subprocess runs to completion but exits with a non-zero return code. The last 500 characters of FFmpeg's stderr (newlines flattened) are appended to the message, so the detail string carries the actual FFmpeg diagnostic; read it first.","triggerScenarios":"Source video is corrupt or truncated (FFmpeg reports Invalid data found when processing input); unsupported codec or container for the requested proxy arguments; output path on a full disk (No space left on device); a stream the proxy filter chain cannot handle such as an audio-only file with no video stream.","commonSituations":"User uploads a file renamed to .mp4 that is actually something else or was only partially uploaded; the disk volume holding the task temp dir is full; the FFmpeg version on the host lacks a codec the command assumes.","solutions":["Read the detail suffix; it is verbatim FFmpeg stderr and names the exact failure (codec, corruption, I/O).","Reproduce manually: run the same ffmpeg command with the source file to see the full stderr.","If the detail mentions invalid data or a missing moov atom, the upload is corrupt; re-upload or validate uploads before task creation.","If the detail mentions no space left, free or enlarge the temp/task storage volume."],"exampleFix":"# manual reproduction to see full stderr\nffmpeg -i corrupted.mp4 -f null - 2>&1 | tail -20","handlingStrategy":"try-catch","validationCode":"# smoke-test the source before task creation\nsubprocess.run(\n    [\"ffmpeg\", \"-v\", \"error\", \"-i\", video_path, \"-f\", \"null\", \"-\"],\n    capture_output=True, timeout=120, check=True,\n)  # raises CalledProcessError on corrupt input before the task starts","typeGuard":null,"tryCatchPattern":"try:\n    proxy = generate_video_proxy(video)\nexcept SoniloError as exc:\n    if str(exc).startswith(\"failed to generate Sonilo video proxy:\"):\n        detail = str(exc).rsplit(\":\", 1)[-1]\n        if \"Invalid data\" in detail or \"moov\" in detail:\n            reject_upload_as_corrupt(video)\n        elif \"space\" in detail.lower():\n            ops_alert_disk_full()\n    raise","preventionTips":["Validate uploads with an ffmpeg decode-to-null pass before accepting them into tasks.","Monitor free space on the task temp volume; the 500-char stderr suffix names the real cause, so log it and never swallow it."],"tags":["ffmpeg","corrupt-input","disk","video"],"backgroundTag":null,"analyzedSha":"1f9f19c2021a68d04df228f33e9099a0c947f6f8","analyzedAt":"2026-08-14T19:41:05.568Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}