“cURL works, but the SDK fails” is a symptom, not a diagnosis. The two requests may differ in method, endpoint, headers, JSON body or streaming behavior. Capture what the application actually sends before changing credentials or client settings.
Capture the request that failed
Record the HTTP method, full URL, header names, JSON body shape, whether streaming is enabled, status code and response body. Keep header values and message content private. A command you typed to imitate the SDK is not proof of the SDK’s wire request.
The existing Python capture helper records the URL and body but does not capture outbound request headers. Use an HTTP trace or a local capture proxy when headers are part of the question.
Then paste the known-working request and the captured or exported app request into the local request comparator. It checks only the text you provide; it never calls either endpoint.
Check method and endpoint first
Compare POST and the full operation path. An OpenAI-compatible label does not mean every client uses the same endpoint: one library may send Chat Completions while another uses Responses, and providers can expose different API prefixes. A 404 points you to inspect the actual host and path; it does not prove the key or model is invalid.
Use the URL-only comparison if you have the two full addresses. The request comparator hides endpoint values and reports only which component differs.
Check explicit and SDK-generated headers
Compare header names and whether their values differ. Keep authorization and API-key values secret. Include user-agent, content type, accept and SDK metadata in the capture, but do not assume that an SDK-identifying header is always the cause.
One Hermes report describes a custom gateway accepting cURL but rejecting OpenAI Python SDK User-Agent and X-Stainless-* headers. The report was closed after configurable custom-provider headers were merged. This is a specific gateway/client case, not evidence that current Hermes or every compatible endpoint is broken.
A separate OpenAI Node SDK report describes another endpoint-specific response to SDK metadata headers. Treat both as reasons to compare a real capture, not as instructions to strip headers globally.
Compare the JSON body without exposing its values
Check the model field, stream setting, output-token field, tools and response-format options. A different stream flag can switch the response path even when the endpoint is identical. The tool reports common setting names only; message text, tool definitions, credentials and unknown fields stay hidden.
Object key order alone does not change JSON meaning. Values still matter: the comparator can say a protected field differs, but it will not print the value or determine whether the endpoint accepts it.
If the captured request matches
Keep the same endpoint, credentials and body while checking the next layer: streaming versus non-streaming, redirects, proxy routing, TLS, timeouts, connection reuse and the client’s SSE parser. A replayed cURL request establishes that the replay worked; it does not establish that the original SDK used the same connection or request.
One OpenAI Codex report says an exact captured Responses request replayed through cURL succeeded while the application failed. That is a different failure layer from an endpoint rejecting SDK headers; neither report establishes how common these cases are.
Source notes
- Hermes #40033 and merged fix #41096
- 9router #597
- OpenAI Codex #24973
- OpenAI Python SDK source for client configuration, including
default_headers
Public issue reports and project source checked 27 October 2026. Reports are self-selected examples, not prevalence estimates. No account, credential, provider inference or live API request was used.
Exact symptom wording and source
Use the quoted text to locate the relevant check. Providers and clients can phrase the same failure differently; compare the complete response before applying a fix.
Reported text:
cURL works but OpenAI Python SDK returns 502 or 403 on a custom gatewayOne custom OpenAI-compatible gateway report implicated the Python SDK User-Agent and X-Stainless headers. Hermes later merged model.default_headers in PR #41096. This is not evidence of a current Hermes defect or a universal reason to strip SDK headers.
HTTP 502: Upstream access forbidden
Hermes Agent #40033, reported 5 June 2026; closed after configurable headers merged
Reported text:
cURL works but OpenAI Node SDK metadata headers receive 403One endpoint-specific report described SDK metadata-header behavior. It does not show how common this is or establish current behavior for other gateways.
OpenAI-compatible endpoint blocks requests from official OpenAI Node SDK unless SDK metadata headers are suppressed
Reported text:
Captured OpenAI Responses request works in cURL replay but application stream failsA single report describes a failing application stream despite a successful cURL replay of captured fields. This does not establish a general client or provider defect and is distinct from a header mismatch.
curl replaying Codex's EXACT captured body + headers — succeeds
OpenAI Codex #24973, open public report checked 27 October 2026