Files
zitadel/apps/docs/lib/grpc-status.ts
T
e8d95f306b docs: add searchable API error reference (#12502)
## Summary
- Add a searchable catalog of every error ID ZITADEL's gRPC/Connect APIs
can return (`content/apis/errors.mdx`), wired into the sidebar next to
"gRPC Status Codes" (with a cross-link added there too). There was
previously no such reference — error IDs are assigned ad hoc at ~3,800
call sites across the backend.
- `scripts/generate-error-reference.ts` scans `internal/**/*.go` and
`backend/**/*.go` for `zerrors.Throw*()` call sites, resolves i18n
messages, and clusters ~3,200 distinct IDs into ~1,160 distinct causes
by (subsystem, gRPC code, message) — so identical causes are merged into
one entry instead of repeated ~3,200 times.
- Detects real ID collisions (same ID thrown for genuinely different
reasons at different call sites) and surfaces them as warnings, rather
than silently merging them.
- Generates a worked example API response for every cause.
- 116 of the highest-impact causes (covering the majority of call sites)
carry an explanation written against the actual source rather than the
raw message text; the rest carry a mechanically derived explanation —
both are visibly labeled by source so the depth of research is
transparent.
- New `ErrorReference` component renders the catalog as a searchable,
collapsible subsystem → gRPC code → cause tree.

The generator is a standalone script (`pnpm generate:error-reference` in
`apps/docs`), not wired into the docs build's `generate` chain, since
scanning the whole Go backend on every docs build would be wasteful. The
generated `data.json` and the curated overrides are committed, the same
way `content/apis/benchmarks/**/output.json` is already committed
despite being externally generated.

## Test plan
- [x] `pnpm nx run @zitadel/docs:check-types` passes
- [x] `pnpm nx run @zitadel/docs:lint` passes
- [x] `pnpm nx run @zitadel/docs:check-links` passes
- [x] Verified locally in `pnpm nx run @zitadel/docs:dev`: page renders,
tree expands/collapses, search filters by ID/message, collision warnings
render correctly (e.g. `AUTHZ-Kl3p0`)

---------

Co-authored-by: Rajat Singh <[email protected]>
Co-authored-by: Claude Sonnet 5 <[email protected]>
Co-authored-by: Marco A. <[email protected]>
2026-09-08 09:47:58 +00:00

47 lines
2.5 KiB
TypeScript

// Mirrors the table in content/apis/statuscodes.mdx. Kept here so
// scripts/generate-error-reference.ts can derive HTTP statuses/example
// responses without hand-duplicating the mapping.
export interface GrpcStatusEntry {
code: number;
name: string;
httpStatus: number;
httpText: string;
}
export const GRPC_STATUS: Record<string, GrpcStatusEntry> = {
OK: { code: 0, name: 'OK', httpStatus: 200, httpText: 'OK' },
CANCELLED: { code: 1, name: 'CANCELLED', httpStatus: 499, httpText: 'Client Closed Request' },
UNKNOWN: { code: 2, name: 'UNKNOWN', httpStatus: 500, httpText: 'Internal' },
INVALID_ARGUMENT: { code: 3, name: 'INVALID_ARGUMENT', httpStatus: 400, httpText: 'Bad Request' },
DEADLINE_EXCEEDED: { code: 4, name: 'DEADLINE_EXCEEDED', httpStatus: 504, httpText: 'Gateway Timeout' },
NOT_FOUND: { code: 5, name: 'NOT_FOUND', httpStatus: 404, httpText: 'Not found' },
ALREADY_EXISTS: { code: 6, name: 'ALREADY_EXISTS', httpStatus: 409, httpText: 'Conflict' },
PERMISSION_DENIED: { code: 7, name: 'PERMISSION_DENIED', httpStatus: 403, httpText: 'Forbidden' },
RESOURCE_EXHAUSTED: { code: 8, name: 'RESOURCE_EXHAUSTED', httpStatus: 429, httpText: 'Too Many Requests' },
FAILED_PRECONDITION: { code: 9, name: 'FAILED_PRECONDITION', httpStatus: 400, httpText: 'Bad Request' },
ABORTED: { code: 10, name: 'ABORTED', httpStatus: 409, httpText: 'Conflict' },
OUT_OF_RANGE: { code: 11, name: 'OUT_OF_RANGE', httpStatus: 400, httpText: 'Bad Request' },
UNIMPLEMENTED: { code: 12, name: 'UNIMPLEMENTED', httpStatus: 501, httpText: 'Not Implemented' },
INTERNAL: { code: 13, name: 'INTERNAL', httpStatus: 500, httpText: 'Internal' },
UNAVAILABLE: { code: 14, name: 'UNAVAILABLE', httpStatus: 503, httpText: 'Service Unavailable' },
DATA_LOSS: { code: 15, name: 'DATA_LOSS', httpStatus: 500, httpText: 'Internal' },
UNAUTHENTICATED: { code: 16, name: 'UNAUTHENTICATED', httpStatus: 401, httpText: 'Unauthorized' },
};
// zerrors.Throw<Kind> function-name suffix -> gRPC status key.
export const THROW_KIND_TO_GRPC_STATUS: Record<string, keyof typeof GRPC_STATUS> = {
Internal: 'INTERNAL',
InvalidArgument: 'INVALID_ARGUMENT',
NotFound: 'NOT_FOUND',
AlreadyExists: 'ALREADY_EXISTS',
PermissionDenied: 'PERMISSION_DENIED',
PreconditionFailed: 'FAILED_PRECONDITION',
Unauthenticated: 'UNAUTHENTICATED',
Unimplemented: 'UNIMPLEMENTED',
ResourceExhausted: 'RESOURCE_EXHAUSTED',
Unavailable: 'UNAVAILABLE',
DeadlineExceeded: 'DEADLINE_EXCEEDED',
Unknown: 'UNKNOWN',
};