In Apollo Client 4, a dashboard query returns data plus an error from one failing resolver; what do errorPolicy none, ignore and all each give the component?
answer
- the default throws the data away
- one policy hides the error
- one policy returns both
- what gets written to the cache
- network errors follow the policy in 4
basics
~20 sWith the default none, useQuery returns the error and undefined data, and nothing is cached. With ignore, it returns and caches the partial data with no error. With all, it returns and caches the partial data together with the CombinedGraphQLErrors error.
solid answer
~40 s`errorPolicy` decides what a hook exposes when the response carries errors. With `none`, the default, `error` is a `CombinedGraphQLErrors`, and `data` is `undefined` even though the server sent the other fields, so the response is not written to the cache. With `ignore`, `error` stays empty and the partial `data` is returned and cached, so the null from the failed field looks like a real value. With `all`, you get both: partial `data`, cached, and the `error`, whose `errors[i].path` tells you which field failed. That is what lets a dashboard render its working panels and flag the broken one. Since Apollo Client 4, network errors follow the policy too: under `all` the error is reported with `data` undefined, and under `ignore` you get neither data nor an error.
code
tsx · 26 linesimport { gql, CombinedGraphQLErrors } from "@apollo/client";
import { useQuery } from "@apollo/client/react";
const DASHBOARD = gql`
query Dashboard {
revenueByRegion { region total }
churnForecast { month rate }
}
`;
export function Dashboard() {
const { data, error, loading } = useQuery(DASHBOARD, { errorPolicy: "all" });
if (loading) return <p>Loading...</p>;
if (!data) return <p role="alert">Dashboard unavailable: {error?.message}</p>;
const churnFailed =
CombinedGraphQLErrors.is(error) &&
error.errors.some((e) => e.path?.[0] === "churnForecast");
return (
<>
<RevenuePanel rows={data.revenueByRegion} />
{churnFailed ? <p role="alert">Churn forecast failed to load.</p> : <ChurnPanel points={data.churnForecast} />}
</>
);
}go deeper
Recall the three values: none returns only the error, ignore returns data and hides the error, and all returns both.
Explain what each policy does to data, error and the cache, using a partial response as the example, and why the default discards partial data.
Show the 4.x change for network errors, the silent-empty trap of ignore, and how to render per-panel failures from error paths under all without leaking error nulls into other views.
Argue whether the client default should stay none or change, weighing correctness-critical screens against availability-first dashboards, and how you would enforce per-query choices in review.
## The situation An internal analytics dashboard loads with one query that fetches several panels: ```graphql query Dashboard { revenueByRegion { region total } churnForecast { month rate } } ``` The `churnForecast` resolver fails. The server returns `revenueByRegion` in `data`, sets `churnForecast` to `null`, and adds one entry to the `errors` array. What the response means is protocol territory. What Apollo Client does with it is decided by one option, **`errorPolicy`**, set on the hook or client-wide through `defaultOptions.watchQuery.errorPolicy`. ## The three values | `errorPolicy` | `error` | `data` | written to the cache | |---|---|---|---| | `none` (default) | `CombinedGraphQLErrors` | `undefined` | no | | `ignore` | `undefined` | partial data | yes | | `all` | `CombinedGraphQLErrors` | partial data | yes | - **`none`** treats any GraphQL error as a failure of the whole operation. The partial data is discarded and is not written to the cache, which avoids caching `null` values produced by errors. The dashboard shows one error state, and the revenue panel disappears along with the broken one. - **`ignore`** pretends nothing went wrong. The component receives `revenueByRegion` and a `null` `churnForecast`, and it cannot tell that the null came from a failure. The null is cached too, so other components reading that field see it as well. - **`all`** returns both. The component renders `revenueByRegion`, checks `CombinedGraphQLErrors.is(error)`, and uses each entry's `path` to show an error in the churn panel only. For a dashboard made of independent panels, **`all`** is usually the right choice, because it is the only policy that keeps the working data and still tells you what failed. ## Network errors now follow the policy In Apollo Client 3, network errors ignored `errorPolicy` and always behaved like `none`. **Apollo Client 4 made network errors respect the policy:** 1. With `none`, the hook reports the error, and a promise API such as `client.query` rejects. 2. With `all`, the promise resolves; `error` holds the network error and `data` is `undefined`, because no GraphQL result arrived. 3. With `ignore`, the promise resolves with **neither `data` nor `error`**. Point 3 is a trap. With `errorPolicy: "ignore"`, a dropped connection on the dashboard renders as an empty screen with no error to show and nothing to log. `ignore` is safe only for optional data, where silently rendering nothing is the desired outcome. ## Where the policy applies and where it does not - `errorPolicy` is applied **after** the link chain. An `ErrorLink` sees the raw result and its errors under every policy. Setting `ignore` does not silence error logging in links. - It applies to mutations too. `useMutation` takes the same option, and with `none` a mutation's partial result is not written to the cache. - It does not change *whether* the server returns partial data. That depends on the schema's nullability. It changes only what the hook exposes and caches. - Suspense hooks such as `useSuspenseQuery` handle errors differently: depending on the policy, they may throw to an error boundary instead of returning `error`. ## Rendering per-panel failures under all With `errorPolicy: "all"` the component has to decide, panel by panel, whether a `null` is data or damage: 1. Narrow the error with `CombinedGraphQLErrors.is(error)`. 2. For each panel, check whether any entry's `path` starts with that panel's root field, such as `churnForecast`. 3. Render the panel's error state for a match. Otherwise render the data, where `null` now genuinely means "no value". Paths also reach inside lists. An entry with the path `["churnForecast", 3, "rate"]` means only the fourth data point failed, so a chart can drop one point instead of the whole panel. The alternative design is one query per panel, each with the default policy. That isolates failures without path matching, but it costs several requests instead of one and loses the single loading state. ## Choosing per query - A settings form that needs every field to be valid: keep **`none`**, because partial data would be misleading. - A dashboard of independent panels: use **`all`**, and render per-panel errors from `error.errors[i].path`. - An optional decoration, such as a "what's new" badge: **`ignore`** is acceptable, provided a failure really should render nothing. Choosing the policy per query, rather than flipping the client default, keeps the strict behaviour where correctness matters and the tolerant behaviour where availability matters.
- With errorPolicy ignore in Apollo Client 4, what does the dashboard show when the network drops?Nothing useful. A network error returns no GraphQL result, so `data` is `undefined`, and `ignore` suppresses the error, so `error` is `undefined` as well. The component sees neither data nor an error and usually renders an empty state with nothing logged. That is why `ignore` suits only optional data, and why `all` is the safer tolerant choice.
- Does setting errorPolicy to ignore stop an Apollo Client 4 ErrorLink from seeing the resolver error?No. The policy is applied after the link chain, when the result is turned into the hook's `data` and `error`. The `ErrorLink` sees the raw response on its way back up and is called with a `CombinedGraphQLErrors` whatever policy the query uses. Logging in the link keeps working, and only the component stops seeing the error.
- Why does Apollo Client 4's default policy skip caching the partial data a failed resolver leaves behind?With `none`, a response that has errors is treated as a failed operation, and the client does not write it to the cache. That avoids storing `null` values produced by errors as if they were real field values, which would leak into every other query reading the same fields. With `ignore` or `all`, the partial data is written, and those nulls do enter the cache.
saying these in an interview costs you the question
- With the default errorPolicy, useQuery still returns the partial data next to the error.
- errorPolicy ignore also stops ErrorLink from seeing the GraphQL errors.
- Network errors always behave like errorPolicy none, whatever you set.
- errorPolicy all keeps partial data out of the cache, returning it only to the hook.
- errorPolicy all makes the server return partial data it would otherwise withhold.