babysor/MockingBird · error · RuntimeError

/text-to-speech failed: status={resp.status_code}, body={res

Error message

/text-to-speech failed: status={resp.status_code}, body={resp.text}

What it means

RuntimeError raised by synthesize() when the Noiz /text-to-speech endpoint returns a non-200 status. The full response body is embedded, since causes range from auth failure to invalid voice ids to oversized text.

Source

Thrown at skills/speak/scripts/noiz_tts.py:117

            )
        }
    elif not voice_id:
        raise ValueError("Either --voice-id or --reference-audio is required.")

    try:
        resp = requests.post(
            url,
            headers={"Authorization": api_key},
            data=data,
            files=files,
            timeout=timeout,
        )
    finally:
        if files and files["file"][1]:
            files["file"][1].close()

    if resp.status_code != 200:
        raise RuntimeError(
            f"/text-to-speech failed: status={resp.status_code}, body={resp.text}"
        )

    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_bytes(resp.content)
    dur = resp.headers.get("X-Audio-Duration")
    return float(dur) if dur else -1.0


def main() -> int:
    parser = argparse.ArgumentParser(description="Simple TTS via Noiz API (no timeline).")
    g = parser.add_mutually_exclusive_group(required=True)
    g.add_argument("--text", help="Text string to synthesize")
    g.add_argument("--text-file", help="Path to text file")
    parser.add_argument("--api-key", required=True)
    parser.add_argument("--voice-id")
    parser.add_argument("--reference-audio", help="Local audio for voice cloning")
    parser.add_argument("--output", required=True)

View on GitHub (pinned to 28dc5e14f1)

Solutions

  1. Read status/body from the message: 401 → fix key, 400 → check voice_id/format/text length, 5xx → retry later
  2. Verify voice_id is from the current voice listing API
  3. Chunk text to <=5000 chars per request
  4. Retry with exponential backoff on 429/5xx

Example fix

# before
text = open("book.txt").read()
synthesize(..., text=text)
# after
for chunk in chunk_text(text, 4500):
    synthesize(..., text=chunk, out_path=Path(f"part_{i}.wav"))
Defensive patterns

Strategy: try-catch

Validate before calling

assert text and len(text) <= 5000, 'text empty or over 5000 chars'

Try / catch

try:
    synthesize(...)
except RuntimeError as e:
    status = int(str(e).split('status=')[1][:3])
    if status in (429, *range(500, 600)):
        time.sleep(2 ** attempt); synthesize(...)
    else:
        raise

Prevention

When it happens

Trigger: POST /text-to-speech with bad Authorization (401), unknown voice_id or unsupported output_format (400), missing reference file upload (400), text over the 5000-char limit, or server 5xx.

Common situations: Expired API key, typo'd voice id, requesting an output format the account tier doesn't support, or very long text submitted without chunking.

Related errors


AI-assisted analysis of babysor/MockingBird@28dc5e14f1 (2026-08-27). Data as JSON: /api/errors/6aa39a15cb443ed9. Report an issue: GitHub.