different-ai/openwork · error
OpenAI Realtime SDP failed: ${sdpResponse.status} ${detail}
Error message
OpenAI Realtime SDP failed: ${sdpResponse.status} ${detail} What it means
The WebRTC offer SDP is POSTed to OpenAI's Realtime calls endpoint with the session's clientSecret. If the HTTP response is not ok, the panel reads the error body (best-effort) and throws with the status code and detail, so WebRTC negotiation with OpenAI failed at the SDP exchange step.
Source
Thrown at apps/app/src/react-app/domains/session/voice/voice-panel.tsx:541
voiceRealtime.channel = channel;
channel.addEventListener("message", (event) => void handleRealtimeMessage(String(event.data)));
channel.addEventListener("close", () => {
if (voiceRealtime.channel === channel) setRuntimeStatus("idle");
});
const offer = await peer.createOffer();
await peer.setLocalDescription(offer);
if (!offer.sdp) throw new Error("Realtime offer did not include SDP.");
setRuntimeStatus("connecting", "Opening voice channel...");
const sdpResponse = await desktopFetch("https://api.openai.com/v1/realtime/calls", {
method: "POST",
headers: { Authorization: `Bearer ${realtimeSession.clientSecret}`, "Content-Type": "application/sdp" },
body: offer.sdp,
});
if (!sdpResponse.ok) {
const detail = await sdpResponse.text().catch(() => "");
throw new Error(`OpenAI Realtime SDP failed: ${sdpResponse.status} ${detail}`.trim());
}
await peer.setRemoteDescription({ type: "answer", sdp: await sdpResponse.text() });
await waitForDataChannelOpen(channel);
setRealtimeDiagnostics("Realtime data channel is open.");
setRuntimeStatus("listening", audioInput ? undefined : "Connected. Send a typed voice command.");
addEntry("system", `Realtime connected with ${realtimeSession.model} and ${realtimeSession.tools.length} OpenWork tools.`);
recordInspectorEvent("voice.connected", { sessionId: props.sessionId, model: realtimeSession.model });
}, [
addEntry,
disconnectRealtime,
handleRealtimeMessage,
props.client,
props.opencodeBaseUrl,
props.openworkToken,
props.sessionId,
setRuntimeStatus,
]);
View on GitHub (pinned to 2b7df46e8a)
Solutions
- Re-mint the voice session (reconnect) to get a fresh clientSecret and retry
- Read the `detail` in the message — 401 => session/secret expired, 400 => inspect SDP/params, 429/5xx => back off and retry later
- Verify network/proxy settings that desktopFetch uses can reach api.openai.com
- Check OpenAI status page if failures are persistent across fresh sessions
Defensive patterns
Strategy: retry
Validate before calling
const sessionContext = await loadVoiceSessionContext(baseUrl, token, sessionId); // mint fresh, don't reuse
if (Date.parse(sessionContext.expiresAt) < Date.now() + 30_000) {
sessionContext = await loadVoiceSessionContext(baseUrl, token, sessionId);
} Try / catch
try {
await connectRealtime(audioInput);
} catch (e) {
if (e instanceof Error && e.message.startsWith("OpenAI Realtime SDP failed:")) {
const status = Number(e.message.match(/SDP failed: (\d+)/)?.[1]);
if (status === 401 || status === 429 || status >= 500) await reconnectWithFreshSession();
else toast.error(e.message);
} else throw e;
} Prevention
- Always mint a fresh realtime session immediately before connecting (clientSecrets are short-lived)
- Retry with backoff on 429/5xx; re-auth on 401
- Check OpenAI status before mass rollouts of realtime features
- Log the response `detail` to distinguish malformed-SDP (400) from auth/expiry issues
When it happens
Trigger: desktopFetch to https://api.openai.com/v1/realtime/calls returns a non-2xx status — e.g. 401 from an expired/invalid clientSecret, 400 from malformed SDP, 429/5xx from OpenAI side; detail is the response body text (empty on read failure).
Common situations: Realtime session context minted too long ago so clientSecret expired; OpenAI outage or region block; network/proxy/TLS issue in desktopFetch; model or voice params in sessionContext rejected by the API (400).
Related errors
- Realtime offer did not include SDP.
- CUA API error ${response.status}: ${errorText.slice(0, 300)}
- latest-mac.yml is missing artifact path/url.
- Failed to fetch latest-mac.yml (${response.status} ${respons
- Request timed out.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/2f56504c3df6b55a.
Report an issue: GitHub.