Integrations

Troubleshooting

The failures you are most likely to hit on day one, and what each actually means.

The failures you are most likely to hit on day one, and what each one actually means. Every error body uses the OpenAI envelope, so branch on error.code rather than the HTTP status — several statuses are used for more than one condition.

401 — the key was not accepted

The gateway looks the key up in its registry at startup. A key that works against OpenAI directly will not work here: you need a Routeplane virtual key, which begins rp_.

Send it as x-routeplane-api-key or as Authorization: Bearer — both are accepted. Health probes (GET /healthz) never require one, so if probes pass and calls 401, the deployment is fine and the key is the problem.

422 with a residency code — sovereign routing refused

This is not a bug. The request carried regulated personal data and a required jurisdiction, and no configured provider is resident there — so the gateway refused rather than sending it somewhere non-compliant.

Residency is a hard constraint: it overrides x-routeplane-provider. If you asked for a provider that cannot serve the region, the region wins. Either add a resident provider or reconsider whether that traffic should carry that data.

422 is used for more than one condition, which is exactly why you should assert on error.code.

The model name is rejected upstream

Most often a leftover provider prefix from a previous gateway. Routeplane passes model through verbatim, so openai/gpt-4o arrives at the provider as that literal string. Use gpt-4o and select the provider with x-routeplane-provider.

My custom headers are not taking effect

Two usual causes. First, the SDK is dropping them — most OpenAI clients need custom headers passed through a default_headers / defaultHeaders option rather than per-call. Second, the header is being sent but overridden: residency is a hard constraint and will override a requested provider.

I cannot read the response headers in a browser

Cross-origin responses only expose headers a server explicitly allows. Routeplane exposes its full branded set through CORS, so x-routeplane-provider, x-routeplane-trace-id and the rest are readable from browser code. If you see them in curl but not in the browser, check that you are reading them from the response object rather than assuming they were filtered.

A streamed response stopped mid-answer

Fallback to another provider is possible only until the first chunk is sent. Once streaming has started the gateway is committed to that provider, so an upstream failure ends the stream instead of silently restarting with a different model — which would otherwise splice two different answers together.

Retry at the application level if you need a complete response.

PII appears masked in a streamed response but not a buffered one

Expected, and worth understanding. Output masking on a streamed response runs per chunk, so a value that spans a chunk boundary can slip through. This is a known limitation rather than a misconfiguration.

The guardrail is never skipped implicitly — the only way to turn masking off is an explicit per-key policy.

429 — which limit?

Read x-routeplane-limit-type, x-routeplane-limit-scope and x-routeplane-limit-policy on the response. They tell you whether it was requests or tokens, at which scope, and under which policy — rather than leaving you to guess which of several limits fired.

Still stuck

Include the x-routeplane-request-id from the failing response. It is the fastest way to correlate what you saw with what the gateway recorded.