HKUDS/DeepTutor · error · VoiceProviderHTTPError
{action} failed with HTTP {status_code}: {detail}
Error message
{action} failed with HTTP {status_code}: {detail} What it means
_raise_for_provider inspects the provider HTTP response; any status >= 400 is converted into a VoiceProviderHTTPError whose message is built by _provider_error_message as "{action} failed with HTTP {status_code}: {detail}" with a trimmed response body. This is the central HTTP-status-to-exception bridge for TTS/STT calls.
Source
Thrown at deeptutor/services/voice/adapters/openai_compat.py:69
"nova",
"onyx",
"sage",
"shimmer",
"verse",
}
def _provider_error_message(action: str, status_code: int, body: str = "") -> str:
detail = (body or "").strip()[:400]
return f"{action} failed with HTTP {status_code}" + (f": {detail}" if detail else ".")
def _raise_for_provider(resp: httpx.Response, action: str) -> None:
"""Surface a provider error with a trimmed body for diagnostics."""
if resp.status_code < 400:
return
body = resp.text or ""
raise VoiceProviderHTTPError(
_provider_error_message(action, resp.status_code, body),
status_code=resp.status_code,
body=body,
)
def _join_api_path(base_url: str, suffix: str) -> str:
"""Append a generic API path to ``base_url`` while preserving query strings."""
base = (base_url or "").strip()
if not base:
raise VoiceProviderError("No endpoint URL configured for this provider.")
head, sep, query = base.partition("?")
suffix = suffix.strip("/")
if head.rstrip("/").endswith(f"/{suffix}"):
return base
joined = f"{head.rstrip('/')}/{suffix}"
return f"{joined}?{query}" if sep else joined
View on GitHub (pinned to 3e82f13042)
Solutions
- Match on the embedded status code: 401/403 → fix API key/entitlements; 404 → fix base_url; 429 → back off / check quota; 5xx → retry with backoff
- Inspect the trimmed body in the exception for the provider's own error message
- Confirm the model name is valid for the configured provider
- If persistent, test the same request with curl against base_url
Defensive patterns
Strategy: try-catch
Try / catch
from deeptutor.services.voice.exceptions import VoiceProviderHTTPError
try:
...
except VoiceProviderHTTPError as exc:
if exc.status_code in (429, 500, 502, 503):
await asyncio.sleep(backoff); retry()
elif exc.status_code in (401, 403):
invalidate_credentials()
else:
raise Prevention
- Branch on status_code, not message text, when you catch VoiceProviderHTTPError
- Monitor 429s to pace request rates
- Smoke-test base_url with a curl call when adding a new provider
When it happens
Trigger: The provider returns 401 (bad key), 403, 404 (wrong base_url/path), 429 (rate limit), or 5xx during TTS synthesis, OpenRouter chat audio synthesis, or transcription.
Common situations: Expired or wrong API key (401), model not entitled (403), wrong endpoint path from a mis-pasted base_url (404), quota exhaustion (429), or transient provider outage (5xx).
Related errors
- TTS provider returned empty audio.
- No endpoint URL configured for this provider.
- Unsupported STT adapter: {name!r}
- No endpoint URL configured for this provider.
- No endpoint URL configured for TTS.
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/bb3ee5c82a49d059.
Report an issue: GitHub.