A GraphQL response contains both a data object and a non-empty errors list — what does that mean?
answer
- Both halves of the body are real
- One failed field is not a failed request
- Nulls in data pair with error entries
- Each entry's path names its hole
basics
~20 sExecution ran and some fields failed while others resolved. The data object holds every field that succeeded, with null in the holes; each errors entry names the field that broke via its path. Both halves are real.
solid answer
~50 sGraphQL executes each field independently, so one field failing does not cancel the operation. When a resolver raises an error, the specification says that field is treated as though it returned `null` and an entry describing the failure is appended to the top-level `errors` list; every other field that resolved keeps its value. A body carrying both keys is therefore a **partial success**, and the correct reading is positional: these named positions failed, the rest of the tree is a real answer. Each errors entry carries a `message` and, whenever the failure maps to a field in the result, a `path` — the response keys and list indices from the root down to the field that broke — which is how you line an error up with the exact hole in `data`. Discarding the body because `errors` is non-empty throws away work the server already paid for.
code
json · 17 lines{
"data": {
"course": {
"title": "Introductory Statistics",
"sections": [
{ "code": "STAT-101-A", "seatsRemaining": 12 },
{ "code": "STAT-101-B", "seatsRemaining": null }
]
}
},
"errors": [
{
"message": "Seat count unavailable",
"path": ["course", "sections", 1, "seatsRemaining"]
}
]
}go deeper
Be ready to say plainly that data and errors can arrive together and that the data half is still real. Recall that a failed field appears as null in place with a matching entry in the errors list.
Explain the mechanics: fields resolve independently, a failing field is treated as returning null, and the entry's path names the exact response position. Expect to walk a sample body and pair every hole with its entry.
Show the consuming policy you would ship: render what resolved, degrade only the affected region, log the paths. Be ready to defend that against a blanket failure branch and to say how you would notice a field degrading every time.
Own the contract question. Decide which partial outcomes are acceptable product behaviour, who arbitrates when client and schema teams disagree, and be ready to argue the cases where a partial render is worse than showing nothing at all.
### Partial success is the normal shape of a GraphQL response A GraphQL server does not execute an operation as one indivisible unit. It walks the selection set field by field, calls the resolver behind each field, and writes the returned value into the response map under that field's response key. Because each field is resolved on its own, one resolver raising an exception is a **local** event: the specification says the failing field is treated as though it returned `null`, and an entry describing the failure is appended to the top-level `errors` list. Every sibling and cousin field that resolved normally keeps its value. The body that reaches the client therefore carries both halves at once — a populated `data` map with holes in it, and a non-empty `errors` list explaining the holes. This is not a degenerate or exotic case. It is the designed outcome of a field error, and any client consuming a GraphQL API will see it routinely in production the first time a downstream dependency behind one field is slow, unavailable, or returns something the resolver cannot use. ### Reading the two halves together The two halves are correlated, not independent. Each item in `errors` carries a required `message`, and — whenever the failure can be attributed to a particular field in the result — a `path`: the list of response keys, with 0-indexed integers for list positions, running from the root of `data` down to the field that broke. That path is the join key between the two halves. Given an entry whose path is `["course", "sections", 1, "seatsRemaining"]`, you know exactly which element of which list lost which field, and you can degrade the one seat-count badge on that one section rather than the page. So the correct reading of a body with both keys is positional: *these named positions failed; the rest of the tree is a real answer the server paid real work to produce*. A client that branches on "is `errors` non-empty?" and throws away `data` is answering a question the protocol never asked, and it discards fields that are perfectly good. ### What the nulls in `data` mean A hole left by a field error is written as `null`, and `null` is also a legitimate value a resolver can return for a nullable field. The wire format does not distinguish them — the discriminator is whether an error path lands at or below that position. If the failing field was declared Non-Null, the server cannot write `null` there, so the null surfaces at the nearest nullable ancestor instead, and that ancestor's whole subtree is gone from the response even though the error path still names the deeper field. There is also a third case that is neither: a field the document never selected simply does not appear as a key at all. Absent, `null`, and `null` with a matching error are three different outcomes, and a client that collapses them will render the wrong thing. ### Why the server behaves this way The alternative — abort the whole operation on the first field error — would make every response as weak as its weakest dependency. A single query commonly fans out to several backends; under all-or-nothing semantics, one flaky service takes the entire screen down for every user, and the blast radius of a minor outage becomes total. Per-field failure lets the schema author decide the blast radius explicitly through nullability: a nullable field confines the damage to itself, a Non-Null field deliberately escalates it upward. The one thing partial success does not do is tell you the request was *fine*. A body with errors is a signal worth recording — with the paths, not just the messages, so you can see which field is degrading and how often — even when the user's screen looks almost normal. ### A concrete example An enrolment client asks for a course and its sections: ```graphql query CourseSeats($id: ID!) { course(id: $id) { title sections { code seatsRemaining } } } ``` The seat-count dependency is unavailable for the second section. The response is: ```json { "data": { "course": { "title": "Introductory Statistics", "sections": [ { "code": "STAT-101-A", "seatsRemaining": 12 }, { "code": "STAT-101-B", "seatsRemaining": null } ] } }, "errors": [ { "message": "Seat count unavailable", "path": ["course", "sections", 1, "seatsRemaining"] } ] } ``` The course title is real. Section A's seat count is real. Exactly one badge on the screen has no number behind it, and the errors list says which. The right render shows both sections, with an inline "seats unavailable" marker on the second — not an empty page, and certainly not a fabricated `0`, which would read as "this section is full" and send a student to a different one. ### The habits interviewers are checking for Three answers mark a candidate as having consumed a GraphQL API only in the happy path: believing the server returns either `data` or `errors` but never both; treating any errors entry as a failed request; and assuming every `null` in `data` is a bug. The corresponding correct instincts are that the halves coexist by design, that errors are positional, and that a null needs to be attributed before it means anything.
- If the errors list is non-empty, is it safe to assume every value in data is unreliable?No. A field error is scoped to the position its path names; values elsewhere in the tree were resolved normally and are as trustworthy as they would be in a clean response. The one caveat is that a failure on a Non-Null field nulls its nearest nullable ancestor, so the missing region can be wider than the error path suggests — but that widening is still visible as nulls, not as silently wrong values.
- Why does the server not abort the whole operation on the first field error?Because a single document usually fans out to several backends, and aborting would make every response as weak as its weakest dependency — one flaky service would blank every screen. Per-field failure keeps the damage local and lets the schema author choose the blast radius deliberately through nullability rather than having it fixed by the protocol.
It is a delivery with a packing slip: most of the order is in the box and the slip lists exactly which lines were short. You unpack what arrived rather than refusing the whole delivery.
saying these in an interview costs you the question
- Says any errors entry means the request failed
- Assumes a server returns data or errors, never both
- Discards data whenever the errors list is non-empty
- Reads only the first message and ignores the paths
- Fills an errored field with a default like zero