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
- Read status/body from the message: 401 → fix key, 400 → check voice_id/format/text length, 5xx → retry later
- Verify voice_id is from the current voice listing API
- Chunk text to <=5000 chars per request
- 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
- Chunk text under 5000 chars
- Verify voice_id against the voices listing
- Retry only transient statuses
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
- /text-to-speech cue {cue.index}: status={resp.status_code},
- /emotion-enhance failed: status={resp.status_code}, body={re
- /emotion-enhance returned no data: {resp.text}
- /emotion-enhance failed: status={resp.status_code}, body={re
- /emotion-enhance returned no data: {resp.text}
AI-assisted analysis of babysor/MockingBird@28dc5e14f1 (2026-08-27).
Data as JSON: /api/errors/6aa39a15cb443ed9.
Report an issue: GitHub.