Your OpenAI-compatible endpoint hangs for 180 seconds, then fails: the four real causes

Silent stalls, 308 self-redirect loops, missing SSE transport, and the relay's own hard timeout. How to tell them apart in 20 seconds.

This failure is so common with third-party API relays that it has a signature: you send a request, nothing happens, and around 180–195 seconds later you get a generic transport or connection error. Nothing in the logs. It is not your network.

Cause 1 — the relay's own hard timeout

178 to 194 seconds, suspiciously consistent, is somebody else's timer. The relay gave up upstream and never told you; your client waited out its window. You are paying three minutes per failed call.

Fix: stop waiting for it. Set your own idle timeout to ~90s so a dead call is declared dead in half the time, then retry on a fresh connection.

streamIdleTimeoutMs: 90000
retryPolicy: { maxRetries: 3, backoffMs: [800, 2000, 6000] }

Cause 2 — silent stall (the connection opens and no bytes ever arrive)

This one is nastier because a health check passes: TCP connects, TLS is fine, the relay accepts the request — then writes nothing. Typically the client tried websocket first and the relay accepted the socket without implementing it, or the relay's own upstream died silently.

Fix: pin the transport. Left on auto, some clients try websocket before HTTP/SSE.

api: openai-completions
transport: sse        # explicit, never auto

Cause 3 — a 308 redirect loop

baseURL ends in /v1 and the relay appends another /v1, or the edge redirects http→https forever. One command shows it:

curl -sS -o /dev/null -w '%{http_code} %{redirect_url}\n' https://relay.example.com/v1/models

A 308 with a redirect target that contains the path twice is your answer. Fix the base URL: exactly one /v1.

Cause 4 — key/credential name mismatch

Not a hang, but the other half of "it worked yesterday". The app reads an env var name (apiKeyEnvName) that isn't set; renaming a provider means updating both the provider block and the credential reference. Check with echo $YOUR_KEY_NAME before touching code.

How to tell these apart in 20 seconds

LLM Relay Doctor runs six checks in order — reachability, redirect behavior, /models with your key, a streaming completion that measures first-byte latency, a non-streaming call, and a verdict — then prints the exact config patch for the working path. 29 USDT, no dependencies, Node 18+.

If you only remember one thing: a hang is not slowness, it is a stall. Lower the idle timeout and add failover; never sit inside someone else's 180-second timer.

LLM Relay Doctor

One command tells you why your API / relay endpoint is broken, in 20 seconds.

Get it — 29 USDT