{"record":{"id":"f687a03082194891","repo":"harry0703/MoneyPrinterTurbo","slug":"sonilo-generation-failed-message","errorCode":null,"errorMessage":"Sonilo generation failed: {message}","messagePattern":"Sonilo generation failed: (.+?)","errorType":"exception","errorClass":"SoniloError","httpStatus":null,"severity":"error","filePath":"app/services/sonilo.py","lineNumber":234,"sourceCode":"    把第一条配乐流按事件顺序写入临时文件，并限制最大体积。\n\n    API 可能同时返回多条候选流；当前产品只需要一条 BGM，所以固定选择\n    stream_index=0。只有收到 complete 事件并通过 FFmpeg 完整解码后才会发布。\n    \"\"\"\n    total_bytes = 0\n    title = \"\"\n    completed = False\n    with open(temp_audio_path, \"wb\") as output:\n        for raw_line in response.iter_lines():\n            if not raw_line:\n                continue\n            event = _parse_event(raw_line)\n            event_type = event[\"type\"]\n            if event_type == \"error\":\n                message = str(\n                    event.get(\"message\") or event.get(\"error\") or \"unknown error\"\n                )\n                raise SoniloError(f\"Sonilo generation failed: {message}\")\n            if event_type == \"title\":\n                title = str(event.get(\"title\") or event.get(\"data\") or \"\")[:200]\n                continue\n            if event_type == \"complete\":\n                completed = True\n                break\n            if event_type != \"audio_chunk\":\n                logger.debug(f\"ignoring unsupported Sonilo event: type={event_type}\")\n                continue\n\n            stream_index = event.get(\"stream_index\", 0)\n            if stream_index != 0:\n                continue\n            encoded_chunk = event.get(\"data\") or event.get(\"audio\")\n            if not isinstance(encoded_chunk, str) or not encoded_chunk:\n                raise SoniloError(\"Sonilo returned an empty audio chunk\")\n            try:\n                chunk = base64.b64decode(encoded_chunk, validate=True)","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/harry0703/MoneyPrinterTurbo/blob/1f9f19c2021a68d04df228f33e9099a0c947f6f8/app/services/sonilo.py#L216-L252","documentation":"Raised when the Sonilo stream itself reports failure: an event with type 'error' arrives, and the message is taken from its 'message' or 'error' field (falling back to unknown error). This is the provider's own error channel (content-policy rejections, prompt problems, server-side generation failures) surfaced verbatim in the raised SoniloError.","triggerScenarios":"POST /v1/video-to-music completes the HTTP handshake with 2xx but the generation later fails server-side and the stream emits an error event. Typical embedded messages: content-policy rejection of the video or prompt, internal generation failure, credit exhaustion mid-generation.","commonSituations":"Prompt text (up to 2000 chars) trips content moderation; the source video contains flagged content; provider capacity issues abort generation; the account runs out of credits after the request started.","solutions":["Read the embedded message; it is the provider's reason and dictates the fix (policy vs capacity vs credits).","For content-policy messages, rephrase the prompt and/or change the video; retrying unchanged will fail again.","For credit or quota messages, top up or switch the API key, then retry.","For transient provider failures, retry the task after a short delay."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"# keep prompts inside policy before submitting\nif len(prompt) > sonilo.MAX_PROMPT_LENGTH:\n    prompt = prompt[: sonilo.MAX_PROMPT_LENGTH]","typeGuard":null,"tryCatchPattern":"try:\n    audio = request_bgm(video, out, prompt)\nexcept SoniloError as exc:\n    msg = str(exc)\n    if msg.startswith(\"Sonilo generation failed:\"):\n        reason = msg.split(\":\", 1)[1]\n        if is_content_policy(reason):\n            fail_task_with_user_visible_reason(reason)  # do NOT retry\n        else:\n            schedule_retry_once()\n    raise","preventionTips":["Surface the provider message to the end user; it names the policy or quota cause and prevents pointless retries.","Sanitize and length-cap prompts client-side and avoid copyrighted or artist names in prompts."],"tags":["sonilo","provider-error","content-policy","streaming"],"backgroundTag":null,"analyzedSha":"1f9f19c2021a68d04df228f33e9099a0c947f6f8","analyzedAt":"2026-08-14T19:41:05.568Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}