How to Configure Custom Error Responses in Easegress: A Complete Guide

Easegress configures custom error responses by chaining a Validator filter to detect request issues with a ResponseBuilder filter that transforms validation failures into fully customized HTTP responses using Go templates, optionally followed by a ResponseAdaptor for final header or body modifications.

Easegress is a cloud-native traffic orchestration system that provides fine-grained control over HTTP request processing. When you need to configure custom error responses in Easegress, the platform leverages a declarative pipeline architecture that combines validators, response builders, and adaptors to transform generic failures into branded API responses or user-friendly HTML pages.

Understanding the Error Response Architecture

Easegress handles errors through a coordinated sequence of filters. Understanding how the Validator, ResponseBuilder, and ResponseAdaptor interact is essential for building effective error handling pipelines.

The Validator Filter

The Validator filter detects problems such as missing headers, invalid JWT tokens, or failed signatures. When validation fails, it calls prepareErrorResponse in pkg/filters/validator/validator.go to inject a minimal response containing only a status code and error tags into the context.

func (v *Validator) Handle(ctx *context.Context) string {
    // …
    prepareErrorResponse(http.StatusBadRequest, "header validator: ", err)
    return resultInvalid
}

This creates a barebones response that stops further processing of the backend but preserves error metadata in the context for downstream filters.

The ResponseBuilder Filter

The ResponseBuilder filter, implemented in pkg/filters/builder/responsebuilder.go, creates a full HTTP response from a template. Its Handle method reads the context, processes the template, and replaces any existing response with the newly constructed one.

func (rb *ResponseBuilder) Handle(ctx *context.Context) (result string) {
    data, err := prepareBuilderData(ctx)
    p := protocols.Get(rb.spec.Protocol)
    ri := p.NewResponseInfo()
    if err = rb.build(data, ri); err != nil { … }
    resp, err := p.BuildResponse(ri)
    ctx.SetOutputResponse(resp)
    return ""
}

The template can reference data from the request, validator tags, or other filter results, allowing dynamic error message generation.

The ResponseAdaptor Filter

The ResponseAdaptor filter, found in pkg/filters/builder/responseadaptor.go, performs post-processing on responses. It can add or remove headers, modify the body, or compress content before the response reaches the client.

func (ra *ResponseAdaptor) Handle(ctx *context.Context) string {
    if newHeader != nil { adaptHeader(egresp.Std().Header, newHeader) }
    if len(newBody) != 0 { egresp.SetPayload([]byte(newBody)) }
    // …
}

This is useful for adding trace IDs, CORS headers, or standardizing error formats across different error sources.

Configuring Custom Error Responses with ResponseBuilder

To configure custom error responses in Easegress, you combine a Validator with a ResponseBuilder in your pipeline YAML definition. The Validator detects the error condition, and the ResponseBuilder constructs the final response payload.

JSON Error Responses for API Validation

This configuration rejects requests missing a required header and returns a structured JSON error:

apiVersion: easegress/v1
kind: Pipeline
metadata:
  name: api-pipeline
spec:
  filters:
    - name: header-validator
      kind: Validator
      headers:
        X-Auth:
          values: ["expected-token"]
    - name: error-response
      kind: ResponseBuilder
      protocol: http
      template: |
        statusCode: 400
        headers:
          Content-Type:
            - application/json
        body: |
          {
            "error": "Invalid authentication token",
            "detail": "{{ .tags }}"
          }

When validation fails, the validator sets statusCode: 400 and tags containing header validator: …. The ResponseBuilder template references {{ .tags }} to include the specific validation failure details in the JSON body.

HTML Error Pages for Web Applications

For web-facing applications, you can return custom HTML error pages instead of JSON:

apiVersion: easegress/v1
kind: Pipeline
metadata:
  name: static-error-pipeline
spec:
  filters:
    - name: path-validator
      kind: Validator
      url:
        exact: /admin
    - name: html-error
      kind: ResponseBuilder
      protocol: http
      template: |
        statusCode: 403
        headers:
          Content-Type:
            - text/html; charset=utf-8
          X-Powered-By:
            - Easegress
        body: |
          <html>
          <head><title>Forbidden</title></head>
          <body><h1>Access denied</h1></body>
          </html>

This configuration returns a 403 Forbidden status with a branded HTML page and custom headers when users attempt to access restricted paths.

Enhancing Error Responses with ResponseAdaptor

After constructing a custom error response, you can use ResponseAdaptor to add headers, modify the body, or apply compression. This is particularly useful for adding trace IDs or security headers to error responses.

apiVersion: easegress/v1
kind: Pipeline
metadata:
  name: error-with-adaptor
spec:
  filters:
    - name: jwt-validator
      kind: Validator
      jwt:
        cookieName: auth
        algorithm: HS256
        secret: "{{ .secrets.jwtSecret }}"
    - name: json-error
      kind: ResponseBuilder
      protocol: http
      template: |
        statusCode: 401
        headers:
          Content-Type:
            - application/json
        body: |
          { "error": "Invalid or missing JWT" }
    - name: add-trace-id
      kind: ResponseAdaptor
      header:
        add:
          X-Trace-Id: "{{ .requestId }}"

In this pipeline, the ResponseAdaptor adds an X-Trace-Id header to the 401 JSON error response, enabling request tracking across your observability stack.

Handling AI Gateway Provider Errors

When using Easegress as an AI Gateway, you may need to handle errors from AI providers like OpenAI. The BaseProvider extracts provider errors into an ErrorResponse struct defined in pkg/object/aigatewaycontroller/protocol/openai.go.

// Inside an AI provider (BaseProvider.ParseTokens)
if fc.StatusCode != http.StatusOK {
    respErr := &protocol.ErrorResponse{}
    err := json.Unmarshal(respBody, &respErr)
    return 0, 0, metricshub.MetricError(respErr.Error.Type)
}

To translate AI provider errors into your custom format, insert a ResponseBuilder after the AI gateway filter:

apiVersion: easegress/v1
kind: Pipeline
metadata:
  name: ai-gateway-pipeline
spec:
  filters:
    - name: ai-proxy
      kind: AIGateway
    - name: translate-ai-error
      kind: ResponseBuilder
      protocol: http
      template: |
        statusCode: {{ .responses.provider.StatusCode }}
        headers:
          Content-Type:
            - application/json
        body: |
          {
            "code": "{{ .responses.provider.Error.Error.Code }}",
            "message": "{{ .responses.provider.Error.Error.Message }}",
            "type": "{{ .responses.provider.Error.Error.Type }}"
          }

This configuration ensures clients receive a standardized JSON error format even when the upstream AI provider returns errors in a different schema.

Summary

  • Validators detect request issues and inject minimal error metadata into the context via prepareErrorResponse in pkg/filters/validator/validator.go.
  • ResponseBuilder constructs full HTTP responses from templates, allowing you to define custom status codes, headers, and bodies in YAML configuration.
  • ResponseAdaptor post-processes responses to add headers, modify bodies, or apply compression before sending to clients.
  • For AI Gateway use cases, the ErrorResponse struct in pkg/object/aigatewaycontroller/protocol/openai.go enables extraction and transformation of provider-specific errors.
  • All configuration is declarative using Easegress Pipeline YAML definitions, allowing version-controlled, reproducible error handling policies.

Frequently Asked Questions

How do I return a custom JSON error when JWT validation fails?

Configure a Validator filter with jwt settings followed by a ResponseBuilder that references the validation context. The ResponseBuilder template can access error details through the context tags and construct a JSON body with the desired schema. Place the ResponseBuilder immediately after the Validator in the pipeline filters array to intercept the error before it reaches the client.

Can I modify error responses based on the original request path?

Yes. The ResponseBuilder template has access to the request object through template variables like {{ .request.URL.Path }}. You can use conditional logic within the template or configure multiple ResponseBuilder filters with different match conditions to return path-specific error formats. For complex routing, combine with the ResponseAdaptor to dynamically adjust headers or bodies based on request metadata.

What is the difference between ResponseBuilder and ResponseAdaptor?

ResponseBuilder creates a complete HTTP response from scratch using a template, replacing any existing response in the context. It is used when you need to generate a full payload, such as when a Validator rejects a request and you want to return a custom JSON or HTML error page. ResponseAdaptor modifies an existing response by adding or removing headers, changing the body, or applying compression. Use ResponseAdaptor when you need to tweak a response that was already generated, such as adding trace IDs to error responses from an AI Gateway.

How do I handle errors from AI providers like OpenAI in Easegress?

When using Easegress as an AI Gateway, the BaseProvider in pkg/object/aigatewaycontroller/providers/base.go automatically extracts provider errors into the ErrorResponse struct defined in pkg/object/aigatewaycontroller/protocol/openai.go. To customize these errors, place a ResponseBuilder filter after the AI Gateway filter in your pipeline. The ResponseBuilder template can access provider error details through variables like {{ .responses.provider.Error.Error.Message }} and transform them into your organization's standard error format before returning them to the client.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →