Error Handling
There are 2 ways you can handle errors in GraphQL: you can either have documents throw an exception if an
error key is located in the payload (and is a list with at least one member) or they can fail silently
and rely on application level code to function.
By default, Houdini will behave "silently" and not throw any exceptions if an error in the query response is
seen. If you want to turn on exceptions, you can specify the details in the throwOnError field of your client config:
export default new HoudiniClient({ url: '...', throwOnError: { // can be any combination of // query, mutation, subscription, and all operations: ['all'], // the function to call error: (errors, ctx) => new Error( `(${ctx.artifact.name}): ` + errors.map((err) => err.message).join('. ') + '.' ) }})Note that mutations always throw on error regardless of the throwOnError configuration. The thrown value is a RuntimeGraphQLError with a .raw field containing the full error payload from the server.
Typing Error Extensions
The GraphQL spec allows servers to include an extensions field on errors with arbitrary data (error codes, stack traces, etc.). Houdini passes these through at runtime, and you can type them by augmenting App.GraphQLErrorExtensions in your app's type declarations:
declare namespace App { interface GraphQLErrorExtensions { code: string timestamp: string }}Once declared, errors[n].extensions will be typed as App.GraphQLErrorExtensions everywhere Houdini exposes errors: query results, mutation responses, subscriptions, and the throwOnError callback.
Error Boundaries
When throwOnError is configured, thrown errors from queries will propagate up the React tree. Wrap the relevant subtree in an error boundary to catch them:
import { ErrorBoundary } from 'react-error-boundary'import type { LayoutProps } from './$types'
export default function Layout({ children }: LayoutProps) { return ( <ErrorBoundary fallback={<div>Something went wrong.</div>}> {children} </ErrorBoundary> )}import { ErrorBoundary } from 'react-error-boundary'
export default function Layout({ children }) { return ( <ErrorBoundary fallback={<div>Something went wrong.</div>}> {children} </ErrorBoundary>)}For mutations, wrap the mutate call in a try/catch — mutations always throw regardless of throwOnError:
try { await mutate({ variables: { ... } })} catch (e) { if (e instanceof RuntimeGraphQLError) { console.error(e.raw) }}try { await mutate({ variables: { ... } })}catch (e) { if (e instanceof RuntimeGraphQLError) { console.error(e.raw) }}