---
title: "Give every GraphQL error a stable code · Agent Wranglers"
url: https://agentwranglers.se/playbook/api-design/graphql-and-grpc/graphql-error-codes
id: API-85
level: Recommended
updated: 2026-10-22
tokens: 775
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Give every GraphQL error a stable code

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [GraphQL and gRPC](https://agentwranglers.se/playbook/api-design/graphql-and-grpc.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: API-85
- Level: Recommended
- Chapter: [GraphQL and gRPC](https://agentwranglers.se/playbook/api-design/graphql-and-grpc.md)
- Rule: Put a fixed, documented code such as `NOT_FOUND` or `FORBIDDEN` in `extensions.code` of every GraphQL error. Clients act on the code, never on the message text.
- Check: A test triggers each documented failure and reads `errors[0].extensions.code`. Each matches the documented code. A forced server crash returns `INTERNAL_SERVER_ERROR` with no stack trace.
- How: GraphQL answers with HTTP 200 for many failures, so the status code tells a client little. The specification reserves `extensions` in each error for extra data. Keep the list of codes in the schema docs. Treat a new code as an additive change, as [keep error types stable](https://agentwranglers.se/playbook/api-design/errors/stable-error-types.md) says for REST. Some failures are part of the normal flow, such as a taken username. Return those as a typed result in the schema instead. Hide internals as [hide internals in errors](https://agentwranglers.se/playbook/api-design/errors/no-internal-details.md) says.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
import { GraphQLError } from 'graphql';

throw new GraphQLError('Invoice not found', { extensions: { code: 'NOT_FOUND' } });
```

### Python example

```python
from graphql import GraphQLError

raise GraphQLError("Invoice not found", extensions={"code": "NOT_FOUND"})
```

## Sources

- [GraphQL specification, Errors](https://spec.graphql.org/September2025/#sec-Errors)

## Related rules

- API-17 [Keep error types stable](https://agentwranglers.se/playbook/api-design/errors/stable-error-types.md) in API design
- API-19 [Hide internals in errors](https://agentwranglers.se/playbook/api-design/errors/no-internal-details.md) in API design

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/api-design/graphql-and-grpc/graphql-error-codes">Agent Wranglers API design playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Load related records in batches](https://agentwranglers.se/playbook/api-design/graphql-and-grpc/graphql-batching.md)
- Next: [Allow only known queries from your own apps](https://agentwranglers.se/playbook/api-design/graphql-and-grpc/graphql-trusted-documents.md)
- [GraphQL and gRPC](https://agentwranglers.se/playbook/api-design/graphql-and-grpc.md)
