Inconsistent HTTP 414 behavior for Apollo Server 4.x automatic persisted queries
0 reputation · 06 Aug 2022, 03:54 UTC
0 reputation · 06 Aug 2022, 03:54 UTC
Automatic persisted queries in Apollo Client send a SHA-256 hash via GET and fall back to POST when the server does not recognize the hash. Because the HTTP specification does not define a maximum URL length, Apollo Server 4.x does not proactively reject long GET request URIs. Instead, an error surfaces only when the underlying Node.js or Express layer throws, which can produce inconsistent behavior across deployments.
This leaves an unresolved design decision about which layer should enforce a safe URL length: the client, the server, or an intermediate gateway. The automatic fallback to POST can also obscure configuration problems by silently retrying with the full query body, making it harder to detect when queries are unnecessarily large. Additionally, future changes to the persisted query link implementation may alter the fallback threshold, potentially breaking clients that depend on the current behavior.
Where should URL length limits for automatic persisted queries be enforced, and what observable signal can distinguish a legitimate POST fallback from an oversized GET that should have been rejected or logged?
33775 reputation · 06 Aug 2022, 05:35 UTC
URL length limits for Automatic Persisted Queries (APQ) should be enforced at the outermost infrastructure layer (e.g., Load Balancer, Ingress Controller, or Reverse Proxy).
Because Apollo Server 4.x is transport-agnostic, it relies on the underlying Node.js or Express layer to handle URI limits. Relying on the application layer creates inconsistency because Node.js default header limits (often 8KB–16KB) vary by version and environment. Enforcing the limit at the gateway ensures that all requests are measured against a single, predictable standard before they reach the Node.js event loop, preventing inconsistent 414 (URI Too Long) or 431 (Request Header Fields Too Large) responses across different pods.
To distinguish between a legitimate APQ fallback and a transport-level rejection, you must monitor the HTTP status code and the response body:
HTTP 200 OK (or 400 Bad Request depending on configuration), but the response body contains a GraphQL error with the code PersistedQueryNotFound. This is the signal the Apollo Client uses to trigger the POST fallback.HTTP 414 URI Too Long or HTTP 431 Request Header Fields Too Large. These are transport-level errors; the request never reaches the Apollo Server logic, and the client may not interpret these as a signal to fallback to POST, resulting in a hard failure.To verify your current threshold and behavior, use curl to send a GET request with a dummy query string exceeding 8KB:
curl -I "http://your-server/graphql?query=...[large_string]..."
If you receive a 414/431, the transport layer is rejecting the request. If you receive a 200 with a PersistedQueryNotFound error, the request reached Apollo Server.
Missing Diagnostic Detail: Are you using a specific cloud load balancer or an ingress controller (e.g., NGINX, Traefik) in front of your Node.js instances? The specific configuration syntax for the limit depends on this layer.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.