Quick answer: A GraphQL operation can return partial data and errors in the same response, because each field is resolved independently and one resolver can fail while the rest succeed. The failed field comes back null inside data, and an errors entry points at it through its path. Mock this mixed shape so you can test the state where one region shows an error and the rest render, instead of only covering full success and total failure.
Why GraphQL returns data and errors together
In a REST call a resource usually succeeds or fails as a unit. A GraphQL query asks for many fields, each running its own resolver against its data source. When one resolver throws, the engine keeps the work the other resolvers did, records the failure, and returns the successful fields, so the response carries both. The transport status is often still 200 because the request was accepted and executed; the failure lives in the body. That is why asserting on status alone misses field-level failures.
A typical partial response looks like this:
{
"data": {
"viewer": { "name": "Ada" },
"orders": null
},
"errors": [
{
"message": "Orders service unavailable",
"path": ["orders"],
"locations": [{ "line": 3, "column": 3 }]
}
]
}
The response shapes worth mocking
There are four distinct shapes, and a client that only handles the first one breaks in production.
| Shape | data |
errors |
What it represents |
|---|---|---|---|
| Full success | Complete | Absent | Every resolver returned |
| Partial data | Some fields null | Present, with paths | A nullable field failed, rest succeeded |
| Non-null bubble | A parent field null | Present, pointing deeper | A non-null field errored and null rose to a nullable parent |
| Top-level failure | Entirely null | Present | Auth, syntax, or a failure that blocks the whole operation |
The non-null bubble is easy to miss. A field declared non-null cannot return null, so the null moves up to the nearest nullable parent, sometimes taking a whole branch. Mocking only the nullable case leaves that propagation untested.
How to mock a partial response
Set up a response override whose body contains both halves, and make errors[].path line up with the null field in data. A path that does not match leaves the client unable to connect the message to the failed region. Include locations and any extensions your real server emits, then vary the override across the four shapes rather than reusing one generic error.
Keep the HTTP status honest too: field-level errors usually arrive with a 200 and the detail in the body, while gateway or transport failures show up as 4xx or 5xx, so your assertions should check both. A desktop API workspace lets you define these GraphQL overrides and assert on the response fields in the same place, including confirming that a null field and its error path agree. Powerduck works this way, so the partial case becomes a repeatable local response instead of waiting for a downstream outage.
How the client should read it
Treat data and errors as two meaningful signals. Do not discard the whole response when errors exists, since the successful fields are still valid; do not ignore errors just because data is present. Walk each error's path to the affected region, show the error there, and render the rest. Check fields for null independently, since a nullable field can be null without an error. Generated types that keep nullability explicit make these checks harder to skip.
Honest limits
A local mock runs in the desktop main process and does not replace the real backend or execute its resolvers, so the partial response you define proves how the client handles that shape, not that the live service will produce it. Real servers differ in their error extensions, how they map failures to HTTP status, and how aggressively non-null errors bubble, so keep a small set of requests against the live API to confirm the actual format. Importing a schema does not deploy a backend, and a passing mock run is not evidence about the upstream services.
Frequently asked questions
Does a 200 GraphQL response mean there were no errors? No. Field-level errors are returned in the body alongside a 200. You have to inspect errors and check null fields rather than rely on the status.
What is the difference between partial data and a top-level failure? Partial data has some successful fields and errors pointing at specific paths. A top-level failure returns data as null, usually from auth, a syntax error, or something that blocks the whole operation.
Why does a non-null field error null out its parent? A non-null field cannot legally return null, so when it errors the null propagates up to the nearest nullable parent. Mock that branch separately because it can remove more of the response than the single failing field.
Should I hide errors if some data loaded? No. Render the successful regions and surface the error at the failed region by its path. Hiding it leaves users looking at an empty area with no explanation.
The bottom line
GraphQL partial failures are a normal response shape, not an edge case, so mock the full set of data-plus-errors combinations and keep each error path tied to its null field. Assert on the body, not just the 200, render successful regions while flagging failed ones, and verify the real server's format separately. For more on this approach, see the API mocking guide hub.
Top comments (0)