Error Catalogue
Catalogue version: 1 — 10 codes
Every GraphQL error response carries an extensions block with a stable string code, the logical http_status, and a typed data payload. Switch on code rather than parsing the human-readable message, which is not part of the stable contract.
Codes
ATTRIBUTE_CONSTRAINT_VIOLATION
A node attribute value failed a schema-defined constraint (e.g. regex, length, range).
- Stability:
evolving - HTTP status:
422
data payload
| Field | Type | Required |
|---|---|---|
node_kind | string | yes |
field_name | string | yes |
constraint | string | yes |
detail | string | null | no |
Example response
{
"data": null,
"errors": [
{
"message": "A node attribute value failed a schema-defined constraint (e.g. regex, length, range).",
"extensions": {
"code": "ATTRIBUTE_CONSTRAINT_VIOLATION",
"http_status": 422,
"data": {
"node_kind": "example",
"field_name": "example",
"constraint": "example",
"detail": "example"
}
}
}
]
}
ATTRIBUTE_INVALID_TYPE
A node attribute received a value that does not match its declared type.
- Stability:
stable - HTTP status:
422
data payload
| Field | Type | Required |
|---|---|---|
node_kind | string | yes |
field_name | string | yes |
expected_type | string | yes |
received_type | string | yes |
Example response
{
"data": null,
"errors": [
{
"message": "A node attribute received a value that does not match its declared type.",
"extensions": {
"code": "ATTRIBUTE_INVALID_TYPE",
"http_status": 422,
"data": {
"node_kind": "example",
"field_name": "example",
"expected_type": "example",
"received_type": "example"
}
}
}
]
}
ATTRIBUTE_REQUIRED
A mandatory node attribute was not provided.
- Stability:
stable - HTTP status:
422
data payload
| Field | Type | Required |
|---|---|---|
node_kind | string | yes |
field_name | string | yes |
Example response
{
"data": null,
"errors": [
{
"message": "A mandatory node attribute was not provided.",
"extensions": {
"code": "ATTRIBUTE_REQUIRED",
"http_status": 422,
"data": {
"node_kind": "example",
"field_name": "example"
}
}
}
]
}
AUTHENTICATION_REQUIRED
The request requires authentication and none was provided or it was invalid.
- Stability:
stable - HTTP status:
401
This code carries no data payload; data is always {}.
Example response
{
"data": null,
"errors": [
{
"message": "The request requires authentication and none was provided or it was invalid.",
"extensions": {
"code": "AUTHENTICATION_REQUIRED",
"http_status": 401,
"data": {}
}
}
]
}
BRANCH_NOT_FOUND
The requested branch does not exist.
- Stability:
stable - HTTP status:
400
data payload
| Field | Type | Required |
|---|---|---|
branch_name | string | yes |
Example response
{
"data": null,
"errors": [
{
"message": "The requested branch does not exist.",
"extensions": {
"code": "BRANCH_NOT_FOUND",
"http_status": 400,
"data": {
"branch_name": "example"
}
}
}
]
}
NODE_NOT_FOUND
The requested node does not exist in the database.
- Stability:
stable - HTTP status:
404
data payload
| Field | Type | Required |
|---|---|---|
node_kind | string | yes |
identifier | string | yes |
Example response
{
"data": null,
"errors": [
{
"message": "The requested node does not exist in the database.",
"extensions": {
"code": "NODE_NOT_FOUND",
"http_status": 404,
"data": {
"node_kind": "example",
"identifier": "example"
}
}
}
]
}
PERMISSION_DENIED
The authenticated user is not permitted to perform the requested action.
- Stability:
stable - HTTP status:
403
data payload
| Field | Type | Required |
|---|---|---|
action | string | null | no |
resource_kind | string | null | no |
Example response
{
"data": null,
"errors": [
{
"message": "The authenticated user is not permitted to perform the requested action.",
"extensions": {
"code": "PERMISSION_DENIED",
"http_status": 403,
"data": {
"action": "example",
"resource_kind": "example"
}
}
}
]
}
SCHEMA_NOT_FOUND
The requested schema kind is not registered in the active schema.
- Stability:
stable - HTTP status:
422
data payload
| Field | Type | Required |
|---|---|---|
kind | string | yes |
Example response
{
"data": null,
"errors": [
{
"message": "The requested schema kind is not registered in the active schema.",
"extensions": {
"code": "SCHEMA_NOT_FOUND",
"http_status": 422,
"data": {
"kind": "example"
}
}
}
]
}
TOKEN_EXPIRED
The authentication token has expired and a silent refresh is required.
- Stability:
stable - HTTP status:
401
data payload
| Field | Type | Required |
|---|---|---|
expired_at | string (date-time) | null | no |
Example response
{
"data": null,
"errors": [
{
"message": "The authentication token has expired and a silent refresh is required.",
"extensions": {
"code": "TOKEN_EXPIRED",
"http_status": 401,
"data": {
"expired_at": "2026-01-01T00:00:00Z"
}
}
}
]
}
UNDEFINED_ERROR
An error not yet covered by the catalogue. Its occurrence indicates a catalogue gap and should be triaged.
- Stability:
stable - HTTP status:
500
This code carries no data payload; data is always {}.
Example response
{
"data": null,
"errors": [
{
"message": "An error not yet covered by the catalogue. Its occurrence indicates a catalogue gap and should be triaged.",
"extensions": {
"code": "UNDEFINED_ERROR",
"http_status": 500,
"data": {}
}
}
]
}
For SDK and third-party consumers
The catalogue is a machine-readable JSON Schema document committed to the repository at schema/error-catalogue.json. Consumers read it from a checkout of the desired Infrahub version. The top-level infrahub_catalogue_version field tracks the wrapper shape. Within a single wrapper version, codes may be added and existing codes may gain additive optional data fields; consumers MUST treat any unrecognised code as UNDEFINED_ERROR. A wrapper-version bump signals an incompatible change to the envelope itself and follows the same deprecation policy as removing a code.
Third-party consumers
External integrators can generate their own bindings or validators directly from schema/error-catalogue.json. For example, to list every published code with jq:
jq '.codes | keys' schema/error-catalogue.json
Known gaps
BRANCH_NOT_FOUNDandSCHEMA_NOT_FOUNDcurrently mirror their existing RESThttp_statusvalues (400/422) rather than a semantically correct404. Aligning them is deferred to a dedicated deprecation-cycle release that bundles the REST status change, the catalogue update, and a changelog fragment.- Not every
ValidationErrorraise site on the GraphQL path has been migrated to the typedATTRIBUTE_*subclasses yet. Un-migrated sites surface asUNDEFINED_ERRORuntil the remaining raise sites are promoted to typed exceptions.