Error Handlers

Error handlers kick in when any of the stages of the regular rule pipeline fail and let you define logic to handle such situations. This page describes the available error handler types in detail.

Some of the error handlers may support or require additional configuration. The corresponding properties are annotated with mandatory, respectively optional to denote configuration requirement, as well as with overridable, not overridable and partially overridable to indicate whether the property can be overridden in a rule pipeline.

Default

This error handler is always there and is executed if no other error handler mechanism is responsible for the error. Actually, there is no need to explicitly configure it. The only exception is to allow overriding the default rule’s error handler chain in a specific rule for performance reasons (if configured error handlers in the default rule should not be considered). This mechanism type doesn’t have any configuration options.

To enable the usage of this mechanism, you have to set the type property to default.

Example 1. Configuring Default error handler to enable referencing it from rules
id: foo
type: default

Generic

This error handler mechanism allows defining fully custom HTTP error responses (status code, headers, and body). It is useful for protocol-specific error semantics, e.g. JSON-RPC style payloads.

To enable the usage of this mechanism, you have to set the type property to generic.

Configuration is mandatory by making use of the config property supporting the following settings:

  • code: int (mandatory, overridable)

    The HTTP status code to return. Allowed range: 100 to 599.

  • headers: array[object] (optional, overridable)

    List of header entries. Each entry must contain exactly one name: value pair. The header values can be templated and have access to the Request object and configured Values.

    Use multiple list entries with the same header name if you need repeated headers.
  • body: string (optional, overridable)

    Optional response body template with access to the Request object and configured Values.

  • values: map[string]string (optional, partially overridable)

    Template values available as Values.

Example 2. Simple generic error response

The configuration below lets heimdall respond with a fixed HTTP 400 Bad Request and a small JSON body.

id: bad_request
type: generic
config:
  code: 400
  headers:
    - Content-Type: application/json
  body: '{"error": "bad request"}'
Example 3. Implementing redirect behavior

The generic error handler below responds with HTTP 302 Found and sets Location to https://127.0.0.1:4433/self-service/login/browser with the return_to query parameter set to the URL encoded value of the current URL.

So, e.g. if heimdall handles a request for https://my-service.local/foo and this handler is selected by the error pipeline, the HTTP response will have code 302 Found and Location set to https://127.0.0.1:4433/self-service/login/browser?return_to=https%3A%2F%2Fmy-service.local%2Ffoo.

id: redirect
type: generic
config:
  code: 302
  headers:
    - Location: https://127.0.0.1:4433/self-service/login/browser?return_to={{ .Request.URL | urlenc }}

To execute this error handler, reference it in the error pipeline of your rule. The optional if clause defines under which conditions it is applied. In the example below, browser-based authentication failures are addressed:

on_error:
  - if: type(Error) == authentication_error && Request.Header("Accept").contains("text/html")
    error_handler: redirect
Example 4. Using generic to model WWW-Authenticate behavior

If the error handler defined below kicks in, heimdall will respond with HTTP 401 Unauthorized and a WWW-Authenticate header set to Basic realm="My fancy app".

id: basic_auth_like
type: generic
config:
  code: 401
  headers:
    - WWW-Authenticate: Basic realm="My fancy app"
Example 5. Agentic MCP or A2A gateway error response

The example below is shown for an MCP gateway scenario and emits a JSON-RPC error payload. For A2A gateway scenarios, the configuration is more or less identical; in most cases only protocol-specific error codes/messages need to be adjusted.

id: mcp_error
type: generic
config:
  code: 200
  headers:
    - Content-Type: application/json
  body: |
    {
      "jsonrpc": "2.0",
      "id": {{ .Request.Body.id | toJson }},
      "error": {
        "code": {{ .Values.errorCode }},
        "message": {{ .Values.message | quote }}
      }
    }
  values:
    errorCode: -32603
    message: "internal error"

In your rule, you would then use it like this:

on_error:
  - if: type(Error) == authentication_error
    error_handler: mcp_error
    config:
      values:
        errorCode: -32001
        message: unauthorized

Redirect

This error handler mechanism allows redirecting the client to another endpoint, e.g. to let the user authenticate. Technically this error handler returns e.g. a HTTP 302 Found response code and sets the HTTP Location header.

The redirect error handler is deprecated and will be removed in heimdall v0.19.0. Migrate to the generic error handler instead.

Equivalent configuration using generic error handler:

id: authenticate_with_kratos
type: generic
config:
  code: 302
  headers:
    - Location: https://127.0.0.1:4433/self-service/login/browser?return_to={{ .Request.URL | urlenc }}

To enable the usage of this mechanism, you have to set the type property to redirect.

Configuration is mandatory by making use of the config property supporting the following settings:

  • to: URL (mandatory, not overridable)

    The url to redirect the client to via the Location header. Can be templated and has access to the Request object.

    When creating query parameters by making use of templates, don’t forget to encode the values using the urlenc function. See also examples below.
  • code: int (optional, not overridable)

    The code to be used for the redirect. Defaults to 302 Found. Both 301 Moved Permanently and 302 Found are authorized.

Example 6. Redirect error handler configuration

The redirect error handler below returns a redirect to https://127.0.0.1:4433/self-service/login/browser with the return_to query parameter set to the URL encoded value of the current URL.

So, e.g. if heimdall handles a request for https://my-service.local/foo and this handler is selected by the error pipeline, the HTTP response to the client will have the code 302 Found set and the Location header set to https://127.0.0.1:4433/self-service/login/browser?return_to=https%3A%2F%2Fmy-service.local%2Ffoo

id: authenticate_with_kratos
type: redirect
config:
  to: https://127.0.0.1:4433/self-service/login/browser?return_to={{ .Request.URL | urlenc }}

To execute this error handler, reference it in the error pipeline of your rule. The optional if clause defines under which conditions it is applied, for example for browser-based authentication failures:

on_error:
  - if: type(Error) == authentication_error && Request.Header("Accept").contains("text/html")
    error_handler: authenticate_with_kratos

WWW-Authenticate

This error handler mechanism responds with HTTP 401 Unauthorized and a WWW-Authenticate HTTP header set. By configuring this error handler you can implement the Basic HTTP Authentication Scheme by also making use of the Basic Auth authenticator. Without that authenticator, the usage of this error handler does actually not make any sense.

The www_authenticate error handler is deprecated and will be removed in heimdall v0.19.0. Migrate to the generic error handler instead.

Equivalent configuration using generic error handler:

id: basic_authenticate
type: generic
config:
  code: 401
  headers:
    - WWW-Authenticate: Basic realm="My fancy app"

To enable the usage of this error handler, you have to set the type property to www_authenticate.

Configuration is mandatory by making use of the config property supporting the following settings:

  • realm: string (optional, overridable)

    The "realm" according to RFC 7235, section 2.2. Defaults to "Please authenticate".

Example 7. Configuration of WWW-Authenticate error handler

If the www authenticate error handler below kicks in, heimdall will respond with HTTP 401 Unauthorized and a WWW-Authenticate header set to Basic realm="My fancy app".

id: basic_authenticate
type: www_authenticate
config:
  realm: "My fancy app"

To execute this error handler, reference it in the error pipeline of your rule. The optional if clause defines under which conditions it is applied:

on_error:
  - if: type(Error) == authentication_error
    error_handler: basic_authenticate

Last updated on Apr 23, 2026