Troubleshooting
401 on the upgrade
Section titled “401 on the upgrade”The HMAC handshake failed. Causes:
- Secret mismatch -
WORKER_SHARED_SECRETdoes not equal the value StandIn holds from pairing. They must match exactly. - Clock skew - the timestamp is outside the freshness window (
HMAC_FRESHNESS_MS, default 60 s). Sync the clocks (NTP). - Replayed handshake - the same
(callId, ts, sig)tuple was already used. This is the single-use guard doing its job; a genuine retry uses a fresh timestamp. - Secret unset - the bridge fails closed if
WORKER_SHARED_SECRETis empty; every upgrade is rejected.
409 Conflict
Section titled “409 Conflict”A live session already owns that call id (a retry or rollout reconnect). The bridge rejects the duplicate so it does not open a second billed Realtime session for one call. It clears when the first session tears down (a silent dead peer clears after the 90 s idle window).
503 Service Unavailable
Section titled “503 Service Unavailable”A connection cap was hit: MAX_CONNECTIONS (default 64) or MAX_CONNECTIONS_PER_IP (default = the total cap). Raise them for a busier deployment, or check for a client that is not closing sockets.
Call connects, then agent-unavailable
Section titled “Call connects, then agent-unavailable”The bridge could not open the OpenAI Realtime session (it retries once). Check that OPENAI_API_KEY is valid and has Realtime access, and that OPENAI_REALTIME_MODEL names a model your account can use. The log line carries the underlying error (401, 404 model not found, connect timeout).
Call ends at ~60 minutes with agent-disconnected
Section titled “Call ends at ~60 minutes with agent-disconnected”The OpenAI Realtime API caps a session at 60 minutes server-side; when it closes the socket, the bridge can only end the Teams call. There is no session migration. Set MAX_CALL_MINUTES below 60 so the bridge governor speaks a goodbye first - the bridge warns about this at startup when the governor would not fire in time.
Call ends with goodbye-timeout
Section titled “Call ends with goodbye-timeout”A goodbye was spoken (StandIn-side assistant.say) but nobody tore the call down within the grace window plus the hard cap. This is the bridge’s backstop doing its job; check the StandIn connection if it recurs.
Governor never fires
Section titled “Governor never fires”MAX_CALL_MINUTES must be a number. A non-numeric or negative value stops startup with a clear error (numeric env vars fail loud), so if the process started, the value parsed. Confirm it is greater than 0 (0 disables the governor).
Startup error about OPENAI_HOST
Section titled “Startup error about OPENAI_HOST”OPENAI_HOST is restricted to *.openai.com so the API key can only be sent to OpenAI. Set OPENAI_HOST_ALLOW_ANY=true only for a proxy you control.
Startup error about OPENAI_VAD, OPENAI_MCP_SERVERS, or VISION_API_URL
Section titled “Startup error about OPENAI_VAD, OPENAI_MCP_SERVERS, or VISION_API_URL”All three are validated at startup and fail loud: OPENAI_VAD must be server_vad or semantic_vad; OPENAI_MCP_SERVERS must be a JSON array of {server_label, server_url} entries with https URLs; VISION_API_URL must be a well-formed http(s) URL without embedded credentials (a private-IP host is allowed for local endpoints, with a warning).
show_image fails on a URL
Section titled “show_image fails on a URL”The URL is SSRF-guarded: public hosts only, at most one redirect hop (re-validated), 5 MB and 10 s bounds, jpeg/png only. A private/metadata address, a second redirect, or an oversized body is refused by design - the agent receives the failure as its tool result and can tell the caller.
Port already in use
Section titled “Port already in use”The CLI prints a friendly hint on EADDRINUSE. Set PORT to a free port.
Where the logs are
Section titled “Where the logs are”The bridge logs one line per event to stdout/stderr, scoped by call id. Set LOG_LEVEL=debug for the verbose relay detail (an invalid value falls back to info). Transcript logging additionally requires LOG_TRANSCRIPTS=true, Teams recording to be active, and (for user turns) OPENAI_TRANSCRIPTION_MODEL.