harry0703/MoneyPrinterTurbo · error · SoniloError
Sonilo returned malformed streaming data
Error message
Sonilo returned malformed streaming data
What it means
Raised by _parse_event when a single NDJSON line from the Sonilo streaming response cannot be decoded as UTF-8 or parsed as JSON. The parser is deliberately strict: truncated lines (network cut mid-chunk), BOMs, HTML error pages injected by a proxy, or garbage all fail here rather than being silently skipped.
Source
Thrown at app/services/sonilo.py:208
_remove_file(proxy_path)
detail = (result.stderr or "").strip().replace("\n", " ")[-500:]
raise SoniloError(f"failed to generate Sonilo video proxy: {detail}")
proxy_size = os.path.getsize(proxy_path) if os.path.isfile(proxy_path) else 0
if proxy_size <= 0 or proxy_size > MAX_PROXY_BYTES:
_remove_file(proxy_path)
raise SoniloError("Sonilo video proxy is empty or exceeds the 300 MB limit")
logger.info(
f"Sonilo video proxy prepared: source={video_path}, size={proxy_size} bytes"
)
return proxy_path
def _parse_event(raw_line: bytes) -> dict[str, Any]:
"""严格解析单条 NDJSON,禁止静默忽略截断或非对象响应。"""
try:
event = json.loads(raw_line.decode("utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
raise SoniloError("Sonilo returned malformed streaming data") from exc
if not isinstance(event, dict) or not isinstance(event.get("type"), str):
raise SoniloError("Sonilo returned an invalid streaming event")
return event
def _stream_audio(response: requests.Response, temp_audio_path: str) -> tuple[int, str]:
"""
把第一条配乐流按事件顺序写入临时文件,并限制最大体积。
API 可能同时返回多条候选流;当前产品只需要一条 BGM,所以固定选择
stream_index=0。只有收到 complete 事件并通过 FFmpeg 完整解码后才会发布。
"""
total_bytes = 0
title = ""
completed = False
with open(temp_audio_path, "wb") as output:
for raw_line in response.iter_lines():
if not raw_line:View on GitHub (pinned to 1f9f19c202)
Solutions
- Capture the failing raw line (add temporary logging of raw_line before the _parse_event call) to see whether it is truncated JSON, HTML, or another framing.
- If it is truncated JSON from a flaky network, treat it as retryable: retry the generation request.
- If it is HTML from a proxy, bypass or fix the proxy for the streaming endpoint.
- If the provider changed framing (for example SSE data prefixes), strip the prefix or adapt _parse_event to the new protocol.
Example fix
# temporary diagnosis
event = _parse_event(raw_line) # before
logger.debug(f"raw sonilo line: {raw_line[:200]!r}")
event = _parse_event(raw_line) # after (remove once diagnosed) Defensive patterns
Strategy: retry
Type guard
def looks_like_ndjson(line: str) -> bool:
s = line.strip()
return s.startswith("{") and s.endswith("}") Try / catch
try:
audio = request_bgm(video, out, prompt)
except SoniloError as exc:
if "malformed streaming data" in str(exc):
retry_with_backoff(request_bgm, attempts=2) # truncation is transient
raise Prevention
- Disable response-rewriting proxies on the streaming endpoint (proxy_buffering off in nginx).
- Log the first raw line on failure once, to distinguish provider framing changes from network truncation.
When it happens
Trigger: The connection drops mid-line so iter_lines yields a truncated JSON fragment; an intercepting proxy returns an HTML 502 page on the streaming endpoint; the provider sends SSE-style 'data: {...}' framing instead of raw NDJSON; a response compressed or garbled by a misconfigured gateway.
Common situations: Unstable networks during long generations; corporate proxies rewriting streaming responses; provider deploys an API change that switches framing; chunked-encoding handling bugs in an intermediary.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Sonilo stream ended before completion
- failed to request ElevenLabs music: {exc}
- failed to connect to Sonilo: {exc}
- Sonilo returned an invalid service response
- Sonilo returned an unexpected service response
AI-assisted analysis of harry0703/MoneyPrinterTurbo@1f9f19c202 (2026-08-14).
Data as JSON: /api/errors/490c5b416b339de4.
Report an issue: GitHub.