babysor/MockingBird · error · RuntimeError
/emotion-enhance failed: status={resp.status_code}, body={re
Error message
/emotion-enhance failed: status={resp.status_code}, body={resp.text} What it means
Same check as noiz_tts.call_emotion_enhance but in render_timeline's _noiz_emotion_enhance: the Noiz /emotion-enhance endpoint returned a non-200 status and the body is surfaced for diagnosis.
Source
Thrown at skills/speak/scripts/render_timeline.py:211
_run_ff(cmd)
# ── Noiz backend ─────────────────────────────────────────────────────
def _noiz_emotion_enhance(
base_url: str, api_key: str, text: str, timeout: int
) -> str:
import requests # noqa: delayed import so kokoro path doesn't need requests
resp = requests.post(
f"{base_url.rstrip('/')}/emotion-enhance",
headers={"Authorization": api_key, "Content-Type": "application/json"},
json={"text": text},
timeout=timeout,
)
if resp.status_code != 200:
raise RuntimeError(
f"/emotion-enhance failed: status={resp.status_code}, body={resp.text}"
)
enhanced = resp.json().get("data", {}).get("emotion_enhance")
if not enhanced:
raise RuntimeError(f"/emotion-enhance returned no data: {resp.text}")
return enhanced
def _bool_form(v: Any) -> str:
return "true" if bool(v) else "false"
def _resolve_reference_audio(ref: str, timeout: int) -> Tuple[Path, Optional[Path]]:
"""Resolve reference_audio to a path. If ref is a URL, download to temp file.
Returns (path_to_use, temp_path_to_cleanup_or_None)."""
if ref.startswith("http://") or ref.startswith("https://"):
import requests
tmp = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)View on GitHub (pinned to 28dc5e14f1)
Solutions
- Add a delay/backoff between per-cue requests to avoid 429
- Check credentials and base_url from the message body
- Retry the single failing cue rather than the whole render
- Skip emotion enhancement (feature flag) if non-essential
Example fix
# before
enhanced = _noiz_emotion_enhance(base_url, key, cue.text, timeout)
# after
try:
enhanced = _noiz_emotion_enhance(base_url, key, cue.text, timeout)
except RuntimeError:
time.sleep(2)
enhanced = _noiz_emotion_enhance(base_url, key, cue.text, timeout) Defensive patterns
Strategy: retry
Validate before calling
r = requests.get(f"{base_url}/health", headers={"Authorization": key}, timeout=5)
assert r.ok Try / catch
for attempt in range(3):
try:
return _noiz_emotion_enhance(base_url, key, cue.text, timeout)
except RuntimeError:
time.sleep(2 ** attempt)
raise Prevention
- Throttle per-cue API calls
- Retry transient failures with backoff
- Make enhancement optional per config
When it happens
Trigger: Per-cue emotion enhancement POST failing with 401 (bad key), 429 (rate limit from many cues in a row), 400, or 5xx.
Common situations: Rate limiting when enhancing a long timeline of cues rapidly, expired credentials, or service outages mid-render.
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}
- /text-to-speech failed: status={resp.status_code}, body={res
- /emotion-enhance returned no data: {resp.text}
AI-assisted analysis of babysor/MockingBird@28dc5e14f1 (2026-08-27).
Data as JSON: /api/errors/419c162343508863.
Report an issue: GitHub.