Skip to main content

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

FieldTypeRequired
node_kindstringyes
field_namestringyes
constraintstringyes
detailstring | nullno

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

FieldTypeRequired
node_kindstringyes
field_namestringyes
expected_typestringyes
received_typestringyes

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

FieldTypeRequired
node_kindstringyes
field_namestringyes

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

FieldTypeRequired
branch_namestringyes

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

FieldTypeRequired
node_kindstringyes
identifierstringyes

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

FieldTypeRequired
actionstring | nullno
resource_kindstring | nullno

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

FieldTypeRequired
kindstringyes

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

FieldTypeRequired
expired_atstring (date-time) | nullno

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_FOUND and SCHEMA_NOT_FOUND currently mirror their existing REST http_status values (400/422) rather than a semantically correct 404. 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 ValidationError raise site on the GraphQL path has been migrated to the typed ATTRIBUTE_* subclasses yet. Un-migrated sites surface as UNDEFINED_ERROR until the remaining raise sites are promoted to typed exceptions.