All skills
apollographql avatar

/apollo-client

@cb48e40 official
by Apollo GraphQLapollographql/skills115 stars
13

Guide for building React applications with Apollo Client 4.x. Use this skill when: (1) setting up Apollo Client in a React project, (2) writing GraphQL queries or mutations with hooks, (3) configuring caching or cache policies, (4) managing local state with reactive variables, (5) troubleshooting Apollo Client errors or performance issues.

Use this Skill: https://skilld.dev/gh/apollographql/skills/apollo-client

This session only. Nothing lands on disk.

referenceserror-handling.md

≈2.8k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Error Handling Reference (Apollo Client 4.x)

Note that Apollo Client 4.x handles errors differently than Apollo Client 3.x. This reference documents the updated error handling mechanisms, error types, and best practices for managing errors in your Apollo Client applications. For older Apollo Client 3.x error handling documentation, see Apollo Client 3.x Error Handling.

Table of Contents

Understanding Errors

Errors in Apollo Client fall into two main categories: GraphQL errors and network errors. Each category has specific error classes that provide detailed information about what went wrong.

GraphQL Errors

GraphQL errors are related to server-side execution of a GraphQL operation:

  • Syntax errors (e.g., malformed query)
  • Validation errors (e.g., query includes a non-existent schema field)
  • Resolver errors (e.g., error while populating a query field)

If a syntax or validation error occurs, the server doesn't execute the operation. If resolver errors occur, the server can still return partial data.

Example server response with GraphQL error:

{
  "errors": [
    {
      "message": "Cannot query field \"nonexistentField\" on type \"Query\".",
      "locations": [{ "line": 2, "column": 3 }],
      "extensions": {
        "code": "GRAPHQL_VALIDATION_FAILED"
      }
    }
  ],
  "data": null
}

In Apollo Client 4.x, GraphQL errors are represented by the CombinedGraphQLErrors error type.

Network Errors

Network errors occur when attempting to communicate with your GraphQL server:

  • 4xx or 5xx HTTP response status codes
  • Network unavailability
  • JSON parsing failures
  • Custom errors from Apollo Link request handlers

Network errors might be represented by special error types, but if an api such as the fetch API throws a native error (e.g., TypeError), Apollo Client will pass it through as-is. Thrown values that don't fulfill the standard ErrorLike interface are wrapped in the UnconventionalError class, which fulfills the ErrorLike interface. As such, you can expect any error returned by Apollo Client to fulfill the ErrorLike interface.

export interface ErrorLike {
  message: string;
  name: string;
  stack?: string;
}

Error Types

Apollo Client 4.x provides specific error classes for different error scenarios:

CombinedGraphQLErrors

Represents GraphQL errors returned by the server. Most common error type in applications.

import { CombinedGraphQLErrors } from "@apollo/client/errors";

function UserProfile({ userId }: { userId: string }) {
  const { data, error } = useQuery(GET_USER, {
    variables: { id: userId },
  });

  // no need to check for nullishness of error, CombinedGraphQLErrors.is handles that
  if (CombinedGraphQLErrors.is(error)) {
    // Handle GraphQL errors
    return (
      <div>
        {error.graphQLErrors.map((err, i) => (
          <p key={i}>GraphQL Error: {err.message}</p>
        ))}
      </div>
    );
  }

  return data ? <Profile user={data.user} /> : null;
}

CombinedProtocolErrors

Represents fatal transport-level errors during multipart HTTP subscription execution.

ServerError

Occurs when the server responds with a non-200 HTTP status code.

import { ServerError } from "@apollo/client/errors";

if (ServerError.is(error)) {
  console.error("Server error:", error.statusCode, error.result);
}

ServerParseError

Occurs when the server response cannot be parsed as valid JSON.

import { ServerParseError } from "@apollo/client/errors";

if (ServerParseError.is(error)) {
  console.error("Invalid JSON response:", error.bodyText);
}

LocalStateError

Represents errors in local state configuration or execution.

UnconventionalError

Wraps non-standard errors (e.g., thrown symbols or objects) to ensure consistent error handling.

Identifying Error Types

Every Apollo Client error class provides a static is method that reliably determines whether an error is of that specific type. This is more robust than instanceof because it avoids false positives/negatives.

import {
  CombinedGraphQLErrors,
  CombinedProtocolErrors,
  LocalStateError,
  ServerError,
  ServerParseError,
  UnconventionalError,
  ErrorLike,
} from "@apollo/client/errors";

// Anything returned in the `error` field of Apollo Client hooks or methods is of type `ErrorLike` or `undefined`.
function handleError(error?: ErrorLike) {
  if (CombinedGraphQLErrors.is(error)) {
    // Handle GraphQL errors
    console.error("GraphQL errors:", error.graphQLErrors);
  } else if (CombinedProtocolErrors.is(error)) {
    // Handle multipart subscription protocol errors
  } else if (LocalStateError.is(error)) {
    // Handle errors thrown by the LocalState class
  } else if (ServerError.is(error)) {
    // Handle server HTTP errors
    console.error("Server error:", error.statusCode);
  } else if (ServerParseError.is(error)) {
    // Handle JSON parse errors
  } else if (UnconventionalError.is(error)) {
    // Handle errors thrown by irregular types
  } else if (error) {
    // Handle other errors
  }
}

GraphQL Error Policies

If a GraphQL operation produces errors, the server's response might still include partial data:

{
  "data": {
    "getInt": 12,
    "getString": null
  },
  "errors": [
    {
      "message": "Failed to get string!"
    }
  ]
}

By default, Apollo Client throws away partial data and populates the error field. You can use partial results by defining an error policy:

Policy Description
none (Default) If the response includes errors, they are returned in error and response data is set to undefined even if the server returns data.
ignore Errors are ignored (error is not populated), and any returned data is cached and rendered as if no errors occurred. data may be undefined if a network error occurs.
all Both data and error are populated and any returned data is cached, enabling you to render both partial results and error information.

Setting an Error Policy

const MY_QUERY = gql`
  query WillFail {
    badField # This field's resolver produces an error
    goodField # This field is populated successfully
  }
`;

function ShowingSomeErrors() {
  const { loading, error, data } = useQuery(MY_QUERY, { errorPolicy: "all" });

  if (loading) return <span>loading...</span>;

  return (
    <div>
      <h2>Good: {data?.goodField}</h2>
      {error && <pre>Bad: {error.message}</pre>}
    </div>
  );
}

Avoid setting a Global Error Policy

While it is possible to set a global error policy using defaultOptions, in practice this is discouraged as it can lead to unexpected behavior and type safety issues. The return types of the TypeScript hooks may change depending on the errorPolicy passed into the hook, and this can conceptually not take global defaultOptions error policies into account. As such, it is best to set the errorPolicy per operation as needed.

Error Links

The ErrorLink can be used to e.g. log error globally or perform specific side effects based on errors happening.

An ErrorLink can't be used to swallow errors fully, but it can be used to retry an operation after handling an error, in which case the error wouldn't propagate. Otherwise, the most common use for ErrorLink is logging.

import { ErrorLink } from "@apollo/client/link/error";

const errorLink = new ErrorLink(({ error, operation, forward }) => {
  if (someCondition(error)) {
    // Retry the request, returning the new observable
    return forward(operation);
  }

  // Log the error for any unhandled GraphQL errors or network errors.
  console.log(`[Error]: ${error.message}`);

  // If nothing is returned from the error handler callback, the error will be
  // emitted from the link chain as normal.
});

Retry Link

Alternatively, you can use the RetryLink from @apollo/client/link/retry to implement retry logic for failed operations.

import { RetryLink } from "@apollo/client/link/retry";

const retryLink = new RetryLink({
  delay: {
    initial: 300,
    max: Infinity,
    jitter: true,
  },
  attempts: {
    max: 5,
    retryIf: (error, operation) => {
      // Retry on network errors
      return !!error && operation.operationName !== "SensitiveOperation";
    },
  },
});

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: from([retryLink, errorLink, httpLink]),
});

Custom Retry Logic

const retryLink = new RetryLink({
  attempts: (count, operation, error) => {
    // Don't retry mutations
    if (
      operation.query.definitions.some(
        (def) =>
          def.kind === "OperationDefinition" && def.operation === "mutation"
      )
    ) {
      return false;
    }

    // Retry up to 3 times on network errors
    return count < 3 && !!error;
  },
  delay: (count) => {
    // Exponential backoff
    return Math.min(1000 * Math.pow(2, count), 30000);
  },
});

Error Boundaries

When using suspenseful hooks, you should use React Error Boundaries for graceful error handling.

Non-suspense per-Component Error Handling

import {
  CombinedGraphQLErrors,
  ServerError,
  ServerParseError,
} from "@apollo/client/errors";

function SafeUserList() {
  const { data, error, loading, refetch } = useQuery(GET_USERS, {
    errorPolicy: "all",
    notifyOnNetworkStatusChange: true,
  });

  // Handle network errors
  if (ServerError.is(error) || ServerParseError.is(error)) {
    return (
      <Alert severity="error">
        <AlertTitle>Connection Error</AlertTitle>
        Failed to load users. Please check your internet connection.
        <Button onClick={() => refetch()}>Retry</Button>
      </Alert>
    );
  }

  // Handle GraphQL errors but still show available data
  return (
    <div>
      {CombinedGraphQLErrors.is(error) && (
        <Alert severity="warning">
          Some data may be incomplete: {error.graphQLErrors[0].message}
        </Alert>
      )}

      {loading && <LinearProgress />}

      {data?.users && <UserList users={data.users} />}
    </div>
  );
}

Source: SKILL.md on GitHub

1 warning16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill is a comprehensive reference and integration guide for Apollo Client 4.x in React applications. No security vulnerabilities, malicious code, or adversarial patterns were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    4/14 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at cb48e40. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 5 months ago
What it can do
Runs commands
metadata
{
  "author": "apollographql",
  "version": "1.0.0"
}
All 1 allowed tools
Bash(npm:*) Bash(npx:*) Bash(node:*) Read Write Edit Glob Grep
Other metadata
compatibility
React 18+, React 19 (Suspense/RSC). Works with Next.js, Vite, CRA, and other React frameworks.
  • React
  • TypeScript
  • apollo-client
  • graphql
  • state-management
  • caching
  • queries
  • mutations
  • suspense

README badge

README badge for apollographql/skills/apollo-client

Guides for building React applications with Apollo Client 4.x, covering queries, mutations, caching, local state, and Suspense integration. Targets React 18+, React 19, Next.js, Vite, and other React frameworks with patterns for client-side apps, server-side rendering, and modern data fetching.

Generated from the current SKILL.md.

Does this skill work with React Server Components and Next.js App Router?
Yes. The skill includes integration guides for Next.js App Router with React Server Components, and supports React 19 with Suspense.
What Apollo Client version does this skill target?
Apollo Client 4.x specifically. The skill does not cover v3 or earlier patterns.
Does this skill cover TypeScript code generation for GraphQL operations?
Yes. The skill includes a reference section on TypeScript Code Generator setup for type-safe operations.
Can I use this skill to configure caching and optimize performance?
Yes. The skill covers InMemoryCache configuration, typePolicies, fetchPolicy strategies, and performance patterns including @defer and @stream.
What frameworks does this skill support beyond client-side React?
It includes integration guides for Next.js App Router, React Router 7 with streaming SSR, and TanStack Start, in addition to client-side apps built with Vite or Create React App.

Generated from the current SKILL.md. These answers refresh after source changes.