{"record":{"id":"4672f7f991d04875","repo":"harry0703/MoneyPrinterTurbo","slug":"failed-to-request-sonilo-music-exc","errorCode":null,"errorMessage":"failed to request Sonilo music: {exc}","messagePattern":"failed to request Sonilo music: (.+?)","errorType":"exception","errorClass":"SoniloError","httpStatus":null,"severity":"error","filePath":"app/services/sonilo.py","lineNumber":306,"sourceCode":"                response = requests.post(\n                    f\"{_base_url()}{VIDEO_TO_MUSIC_PATH}\",\n                    headers={\"Authorization\": f\"Bearer {get_api_key()}\"},\n                    files={\"video\": (Path(video_path).name, video_file, \"video/mp4\")},\n                    data={\"prompt\": prompt} if prompt else None,\n                    stream=True,\n                    timeout=_request_timeout(),\n                )\n                with response:\n                    if not response.ok:\n                        raise SoniloError(\n                            f\"Sonilo generation failed ({response.status_code}): \"\n                            f\"{_safe_response_error(response)}\"\n                        )\n                    total_bytes, title = _stream_audio(response, temp_audio_path)\n        except requests.RequestException as exc:\n            # iter_lines() 期间的网络中断同样属于 requests 异常，不能只捕获\n            # 建立连接阶段，否则半条音频可能让任务直接异常退出而无法降级。\n            raise SoniloError(f\"failed to request Sonilo music: {exc}\") from exc\n\n        try:\n            bgm_service.validate_audio_file(temp_audio_path, timeout_seconds=120)\n        except (bgm_service.BgmUploadError, bgm_service.BgmServiceError) as exc:\n            raise SoniloError(\"Sonilo returned audio that FFmpeg cannot decode\") from exc\n        os.replace(temp_audio_path, output_path)\n        temp_audio_path = \"\"\n        logger.info(\n            f\"Sonilo background music generated: output={output_path}, \"\n            f\"size={total_bytes} bytes, title={title or '-'}\"\n        )\n        return output_path\n    finally:\n        _remove_file(temp_audio_path)\n\n\ndef generate_bgm(\n    video_path: str,","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/harry0703/MoneyPrinterTurbo/blob/1f9f19c2021a68d04df228f33e9099a0c947f6f8/app/services/sonilo.py#L288-L324","documentation":"Raised when any requests.RequestException occurs across the whole video-to-music call: connection setup, headers, body upload, and streaming via iter_lines (the except deliberately wraps the entire with-block so mid-stream drops are caught too). The original requests exception text is embedded. This is the generic transport-failure bucket: DNS, TLS, refused connections, read timeouts, resets.","triggerScenarios":"DNS failure resolving the sonilo_base_url host; TLS certificate error behind a corporate MITM proxy; connection reset mid-upload of the video proxy; read timeout because generation stalls longer than the configured read timeout (capped at 1800 seconds); proxy or firewall blocking outbound HTTPS.","commonSituations":"A wrong sonilo_base_url configured (typo, internal URL unreachable from the server); egress firewalls on production hosts; flaky networks during long streams; self-signed-certificate proxies; read timeout configured too low for six-minute generations.","solutions":["Read the embedded exception: name-resolution failure means fix sonilo_base_url or DNS; read timeout means raise the sonilo_timeout config (capped at 1800); SSL errors mean fix cert trust or bypass the MITM proxy; connection refused means a firewall or egress rule.","Verify basic reachability from the app host with a curl HEAD request to the services endpoint.","For long generations, set the sonilo_timeout config near the 1800-second ceiling.","Wrap the task-level call in a bounded retry (1-2 attempts with backoff) since transport errors are usually transient."],"exampleFix":"# before (single attempt)\nresult = sonilo._request_bgm(video, out, prompt)\n# after (bounded retry for transport errors)\nfor attempt in range(3):\n    try:\n        result = sonilo._request_bgm(video, out, prompt)\n        break\n    except sonilo.SoniloError as exc:\n        if attempt == 2 or \"failed to request Sonilo music\" not in str(exc):\n            raise\n        time.sleep(2 ** attempt)","handlingStrategy":"retry","validationCode":"import requests, sonilo\n\n# cheap reachability check before the long job\ntry:\n    requests.get(\n        f\"{sonilo._base_url()}{sonilo.SERVICES_PATH}\",\n        headers={\"Authorization\": f\"Bearer {sonilo.get_api_key()}\"},\n        timeout=10,\n    )\nexcept requests.RequestException as exc:\n    logger.warning(f\"Sonilo unreachable before task: {exc}\")","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        output = sonilo._request_bgm(video, out, prompt)\n        break\n    except sonilo.SoniloError as exc:\n        if \"failed to request Sonilo music\" not in str(exc) or attempt == 2:\n            raise\n        time.sleep(2 ** attempt)  # transport errors are transient; DNS/cert faults exhaust fast","preventionTips":["Configure sonilo_timeout generously (up to 1800 seconds) for long generations; short read timeouts cause spurious failures.","Fix DNS, TLS, and egress rules at the infrastructure layer; retries cannot cure an unreachable base URL."],"tags":["sonilo","network","timeout","retry"],"backgroundTag":null,"analyzedSha":"1f9f19c2021a68d04df228f33e9099a0c947f6f8","analyzedAt":"2026-08-14T19:41:05.568Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}