Persisted query missing from registry returns inconsistent HTTP status
0 reputation · 26 Mar 2020, 11:30 UTC
0 reputation · 26 Mar 2020, 11:30 UTC
Goal: Diagnose what HTTP status code and response body a GraphQL server should return when a client submits a persisted query ID that is missing from the server registry.
The GraphQL specification does not prescribe behavior for an unknown persisted query ID. Server implementations diverge: Apollo Server typically returns 400 Bad Request, while GraphQL.js may return 200 OK with an error object in the response body. Clients that branch on HTTP status can misinterpret the response or treat it as a network failure.
Behavior varies by server library and release, so the exact versions in use must be confirmed before relying on any default.
Should an unknown persisted query ID produce a 400 status or a 200 response containing a GraphQL error?
How can a client reliably distinguish a registry miss from other request errors when status codes differ across servers?
What normalized response should a gateway return to clients before forwarding upstream results?
The GraphQL specification does not define an HTTP status code for an unknown persisted-query ID. A missing registry entry is a client request error, so 400 Bad Request is the more useful default. A 200 OK response containing a GraphQL errors array is legal but makes client handling fragile. If you operate a gateway, normalize upstream variance to a single contract before clients see it.
A missing persisted-query ID is usually detected before execution, which many servers classify as a bad request. Other implementations treat lookup failure as an execution error and still return HTTP 200 because the transport request itself was well-formed.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"errors": [
{
"message": "Persisted query not found",
"extensions": {
"code": "PERSISTED_QUERY_NOT_FOUND"
}
}
]
}
Do not branch only on HTTP status. Check status first, then inspect errors[].extensions.code. Treat 400 with PERSISTED_QUERY_NOT_FOUND as a registry miss; treat other 400s as malformed requests; treat 200 with errors as server-specific unless normalized by a gateway.
curl -i -X POST https://api.example.com/graphql -H "Content-Type: application/json" -d '{"extensions": {"persistedQuery": {"sha256Hash": "deadbeef..."}}}'
Compare the status and body against the expected normalized shape. If the upstream returns 200, the gateway must rewrite it to 400 before forwarding to clients.
Assumption: you are using HTTP transport for GraphQL and can insert a gateway or middleware. Version-specific defaults may change; verify after upgrades.
Use comments to ask for clarification. Post a solution as an answer.
5,960 reputation · 26 Mar 2020, 21:59 UTC
When a persisted query ID is absent from the server registry, HTTP status and response body often diverge: some servers return 400 Bad Request with a GraphQL error, while others return 200 OK with the error embedded in the response body. Clients seeking reliable detection should inspect the errors array for a persisted-query-related marker rather than depending on status code alone. A quick verification step is to send a POST request with an unknown persisted query ID and observe whether the status is 400 or 200, then inspect the errors field accordingly.