# Errors

URL: https://developers.uidu.org/docs/foundations/errors

> How to handle UiduError and the underlying GraphQL/network failure modes.

Every SDK function throws `UiduError` on failure — no exceptions slip through untyped.

## The shape

```ts
import { UiduError } from '@uidu/client';

class UiduError extends Error {
  readonly code: string; // one of the codes below
  readonly graphQLErrors?: ReadonlyArray<GraphQLError>;
  readonly cause?: unknown;
}
```

## When to use which code

| Code            | Cause                                                                                                                                                                                                        |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GRAPHQL_ERROR` | The server returned a 200 OK with `errors[]` in the body. Typical reasons: schema validation failed, the requested entity is restricted by permissions, or a resolver crashed. `graphQLErrors` is populated. |
| `NETWORK_ERROR` | The request never got a useful HTTP response — DNS, TLS, timeout, connection reset, CORS preflight failure. `cause` holds the underlying transport error.                                                    |
| `CONFIG_ERROR`  | `createClient` was given neither a `workspace` nor an `endpoint`. Thrown when the client is built, not per request.                                                                                          |
| `TOKEN_ERROR`   | The client's `getToken` failed — in a custom app, the bridge couldn't produce a session token. `cause` holds the original error.                                                                             |

## Handling pattern

```ts
import { getPage, UiduError } from '@uidu/client';

try {
  const page = await getPage(client, { projectId, slug });
  return page;
} catch (err) {
  if (err instanceof UiduError) {
    if (err.code === 'GRAPHQL_ERROR') {
      // Server-side reasoning. Log err.graphQLErrors for the details.
      console.warn('Schema error:', err.graphQLErrors);
      return null;
    }
    if (err.code === 'NETWORK_ERROR') {
      // Retry, or surface a "service unavailable" page.
      throw err;
    }
  }
  throw err;
}
```

## Don't swallow

A common mistake: wrap every SDK call in `try/catch (_) {}` and return `null`. That hides server-side problems (a tags field crashing the resolver, a permission gate triggering a 500). Let `NETWORK_ERROR` bubble; only swallow `GRAPHQL_ERROR` if you know the schema can validly reject the request (e.g. a missing slug).

## Inspecting the underlying GraphQL errors

```ts
catch (err) {
  if (err instanceof UiduError && err.code === 'GRAPHQL_ERROR') {
    for (const e of err.graphQLErrors ?? []) {
      console.log(e.message);
      console.log(e.path);
      console.log(e.extensions); // server-side error metadata
    }
  }
}
```

<Callout type="info">
  If a query fails with no error body (empty `errors[]` and the field nulled out), it's typically a Rails-side resolver crash. Drop the offending field from the selection and file a server-side bug.
</Callout>
