skip to content

questions

3

In GraphQL, what is the difference between a request error and a field error?

level: juniorimportance: must knowfreq 72%

answer

  1. Two classes, split by timing
  2. Before execution versus during it
  3. Nothing ran versus one field failed
  4. Absent data key versus a hole
  5. Parse, validate, coerce variables

basics

~20 s

A request error happens before execution — the document failed to parse or validate, or its variables would not coerce — so nothing ran and there is no data entry. A field error is raised while resolving one field, leaving data partial.

solid answer

~50 s

GraphQL's specification defines exactly two error classes, separated by **when** the failure occurs. A **request error** is raised before execution begins — a parse failure, a validation failure against the schema, no matching operation, or a variable value that cannot be coerced to its declared type. Nothing executed, so there is no partial result and the response carries no `data` entry at all. A **field error** is raised while resolving one field: the resolver threw or timed out, or returned a value that cannot be coerced to the declared type. That field becomes `null`, an entry is appended to the errors list, and execution continues for every sibling field — so `data` is present and populated with a hole in it. The practical discriminator for a client is the `data` entry: absent means nothing ran; present, even as `null`, means execution happened and the failure is per-field.

code

json · 8 lines
json
{
  "errors": [
    {
      "message": "Cannot query field 'adjustor' on type 'Claim'. Did you mean 'adjuster'?",
      "locations": [{ "line": 3, "column": 34 }]
    }
  ]
}

go deeper

for a junior

Be ready to state the split in one sentence: request errors happen before anything runs and return no data, field errors happen while resolving one field and return partial data. Naming parse and validation failures as request errors is the expected floor.

for a middle

Explain the mechanics: validation and variable coercion both run before execution, a field error nulls its own field and lets siblings continue, and the presence or absence of the data entry is the discriminator a client should branch on.

for a senior

Show that you handle the two classes differently in production code — a request error is a deterministic contract break tied to a client build, a field error is a runtime fault in one dependency that still leaves a renderable result.

for a principal

Own the consequence for the platform: the class split is what lets one graph serve partial results instead of failing whole screens, and it is the contract you hold client teams to when they wire error handling and alerting.

## The specification names two classes, and only two GraphQL's error model is deliberately small. A failure is either a **request error**, raised before execution begins, or a **field error**, raised while one particular field is being resolved. Anything else you might loosely call an error — a reset socket, a proxy that returned an HTML page, a body that never arrived — is a transport failure and is not part of a GraphQL response at all, because there is no GraphQL response. The two classes differ only in *when* the failure happens. That single difference decides everything the client sees. ## What raises a request error A request error means the server never started executing the operation. The usual causes, in the order a server works through them: - **Parse failure.** The text is not valid GraphQL syntax — an unclosed brace, an unterminated string. - **Validation failure.** The document parses, but does not hold up against the schema: a field the type does not declare, a fragment spread on a type it can never apply to, an argument name that does not exist. (*Which* rules are checked is a separate subject; that they run before execution is this one.) - **Operation selection failure.** The document holds several operations and the request named none of them, or named one the document does not contain. - **Variable coercion failure.** The document is entirely legal, but a value supplied in the `variables` map cannot be coerced to the declared variable type — a string where the operation declares `Int!`, no value at all for a non-null variable that has no default, an enum value the enum type does not define. That last cause is the one candidates miss, because nothing about the *document* was wrong. Coercing variable values happens after validation and before the first resolver runs, so a failure there is still pre-execution and still a request error. Because nothing executed, there is no partial result to report — so the response carries no `data` entry at all. Not `null`: absent. (The envelope keys themselves are their own subject; what belongs here is *why* the entry is missing — there was never any data to put in it.) ## What raises a field error A field error is raised during execution, while resolving one field of one object: - the resolver raised, rejected or timed out — a downstream service was unreachable, an authorization check failed, an unexpected exception escaped; - the resolver returned a value the executor cannot coerce to the field's declared type — a string that is not a member of the declared enum, a non-numeric value for `Int`; - a `null` arrived in a Non-Null position, which is itself raised as a field error at that position. The executor's response is fixed: the field resolves to `null`, an entry is appended to the errors list, and **execution continues**. Sibling fields that had nothing to do with the failure are still resolved and still appear in the result. The client therefore gets a `data` map that is present and populated, with a hole in it. (How far that hole spreads when the failing field is declared Non-Null is a separate subject of its own.) ## Worked example: an insurance claims graph A claims portal asks a policy for its open claims and, for each, the assigned adjuster: ```graphql query PolicyClaims($policyId: ID!) { policy(id: $policyId) { claims(first: 14) { reference adjuster { displayName } } } } ``` Two very different bad days: **Day one** — a client build ships with `adjustor` instead of `adjuster`. Validation rejects the document. No resolver runs, no claims are fetched, no audit row is written, and the response has an errors list and no `data` key. The portal shows an empty screen, and it will show an empty screen on every retry until the client is rebuilt. **Day two** — the document is fine, but the adjuster directory times out for 3 of the 14 claims. Execution continues: all 14 claims come back with their `reference`, three of them carry `adjuster: null`, and the errors list holds three entries. The portal can render the claim list and grey out three names. Same endpoint, same schema, completely different obligation on the client. ## The discriminator you can code against Not the transport status, and not the presence of an errors list — both classes produce one. The dependable signal is the `data` entry itself: **absent means a request error and nothing ran; present — even when its value is `null` — means execution began and you are looking at field errors.** ## Specified versus conventional Specified: the two classes, when each is raised, that a request error leaves no `data` entry, that a field error nulls its field and lets execution continue. Conventional: a machine-readable `code` inside an error's extensions, any particular mapping onto HTTP status codes, retry policy, and modelling *expected* domain failures as schema types rather than as errors at all. None of those are rules of the specification, and attributing them to it is a quick way to lose an interviewer's confidence. ## Confusions worth pre-empting - **"If `errors` is present, ignore `data`."** Discarding a populated result because one field of forty failed is the most common client bug in GraphQL codebases. - **"A validation failure is a field error, because the message names a field."** The class is decided by *when* the failure happened, not by what its message mentions. Nothing executed, so nothing can be a field error. - **"A field error aborts the operation."** It aborts that field. Siblings keep going.

  • Can a single GraphQL response contain both request errors and field errors?
    No. A request error means execution never began, so no field could have been resolved and no field error could exist. Once execution starts, the operation is past the point where a request error can be raised. A response is therefore on one side of the line or the other: either it never ran and has no `data` entry, or it ran and any errors it carries are field errors.
  • Is variable coercion part of validation or part of execution?
    Neither, strictly — it sits between them. The document is parsed and validated against the schema first, then the supplied variable values are coerced against the variable definitions, then execution begins. A coercion failure is a request error even though the document itself was perfectly valid, which is why an unchanged, previously-working document can still fail before anything runs.
  • Does a request error guarantee the server did no work?
    It guarantees no field resolver ran, so no mutation field executed and no resolver-level side effect happened. It does not mean the server was idle: it still parsed, validated, likely authenticated the caller, and wrote logs and metrics. For reasoning about side effects — especially for mutations — the useful guarantee is the narrow one: nothing in the schema's execution path was invoked.

A request error is a compiler refusing to build the program; a field error is a running program logging that one subtask failed while the rest of the job still produces output.

saying these in an interview costs you the question

  • Says any response with errors should be discarded
  • Calls a validation failure a field error
  • Thinks a field error aborts the whole operation
  • Believes data is null rather than absent on request errors
  • Claims the HTTP status tells you which class it is
  • Says a valid document can never fail before execution

context

open as a page

In GraphQL, when is an enum value outside the schema's definition a request error rather than a field error?

level: middleimportance: should knowfreq 41%

basics

~20 s

The direction of coercion decides. An enum value the schema does not declare is a request error when a client sends it, so nothing runs; it is a field error when a resolver returns it, nulling that field.

open as a page

In a GraphQL API, why should request errors and field errors drive different retry and alerting rules?

level: seniorimportance: should knowfreq 44%

basics

~20 s

A request error is deterministic — the same document fails identically forever — so retrying is waste and the signal is a client or schema release. A field error is a transient dependency fault where a retry can succeed.

open as a page