can1357/oh-my-pi · error · ProviderHttpError
${options.label} failed (${resp.status}): ${detail.slice(0,
Error message
${options.label} failed (${resp.status}): ${detail.slice(0, 300)} What it means
postSpeechRequest is the shared POST for cloud TTS providers (e.g. xAI, ElevenLabs). When the HTTP response is not ok, it reads the body (first 300 chars) and throws a ProviderHttpError carrying the status code and response headers. postSpeechRequest catches ProviderHttpError and converts it to { errorText } so the tool returns a friendly error result.
Source
Thrown at packages/coding-agent/src/tools/tts.ts:132
let response: Response;
try {
response = await withAuth(
options.apiKey,
async key => {
const resp = await options.fetchImpl(options.url, {
method: "POST",
headers: {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
"User-Agent": USER_AGENT,
},
body: JSON.stringify(options.payload),
signal: combinedSignal,
});
if (!resp.ok) {
const detail = await resp.text();
throw new ProviderHttpError(
`${options.label} failed (${resp.status}): ${detail.slice(0, 300)}`,
resp.status,
{ headers: resp.headers },
);
}
return resp;
},
{ signal: combinedSignal },
);
} catch (error) {
const status = (error as { status?: unknown }).status;
if (error instanceof Error && typeof status === "number") {
return { errorText: error.message };
}
throw error;
}
return new Uint8Array(await response.arrayBuffer());
}View on GitHub (pinned to 9690622007)
Solutions
- Read the embedded detail text — it contains the provider's own error message and status code
- For 401/403, refresh credentials: re-run /login → xAI Grok OAuth or update XAI_API_KEY
- For 429, wait and retry with backoff; for 400, check voice_id, language, text length, and output_format against provider limits
- For 5xx, retry later or fall back to local TTS if configured
- Note the 60 s AbortSignal.timeout fence: a timeout will surface as an abort, not this error
Example fix
// before
await synthesize({ text, voice_id: "custom-voice-xyz" }) // 400: voice not found
// after
const voices = await provider.listVoices();
await synthesize({ text, voice_id: voices[0].id }) // use a valid voice id Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight checks before calling the tool
if (!process.env.XAI_API_KEY && !hasOAuthToken()) throw new Error("No TTS credentials configured");
if (params.text.length > 4096) throw new Error("Text exceeds provider character limit"); Type guard
function isProviderHttpError(e: unknown): e is ProviderHttpError {
return e instanceof ProviderHttpError || (e instanceof Error && typeof (e as { status?: unknown }).status === "number");
} Try / catch
const result = await ttsTool.run(params, ctx);
if (result.isError) {
const text = result.content[0]?.text ?? "";
const statusMatch = text.match(/failed \((\d+)\)/);
const status = statusMatch ? Number(statusMatch[1]) : 0;
if (status === 401 || status === 403) {
// prompt user to refresh credentials (re-login / XAI_API_KEY)
} else if (status === 429) {
// back off and retry later
} else if (status >= 500) {
// provider outage: retry with backoff or fall back to local TTS
}
} Prevention
- Verify API credentials (XAI_API_KEY or OAuth) before invoking TTS
- Respect provider limits: text length, valid voice_id, supported language/output_format
- Add backoff/retry around 429 and 5xx statuses
- Check the error's embedded detail text — it contains the provider's exact reason
- Remember the 60 s timeout fence: long syntheses will abort rather than hang
When it happens
Trigger: The TTS provider returns any non-2xx status: 401 (invalid/expired API key), 400 (payload validation, voice_id not found, text too long), 402/429 (quota or rate limit), 500/503 (provider outage), 422 (unsupported language or output format combination).
Common situations: Expired or missing XAI_API_KEY / OAuth token; voice_id no longer offered by the provider; text exceeding provider character limits; rate limiting after a burst of syntheses; provider-side downtime; wrong region base URL.
Related errors
- Devin AssignModel error ${response.status} ${response.status
- GitLab Duo Workflow create failed with HTTP ${response.statu
- ${response.status} ${response.statusText}: ${text}
- ${context}: ${response.status} ${response.statusText}${suffi
- HTTP ${response.status}: ${text}${suffix}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/066163c914c744e4.
Report an issue: GitHub.