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

> Learn to configure custom error responses in Easegress using Validator and ResponseBuilder filters. Create tailored HTTP responses with Go templates for enhanced error handling.

- Repository: [easegress-io/easegress](https://github.com/easegress-io/easegress)
- Tags: how-to-guide
- Published: 2026-03-01

---

**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`](https://github.com/easegress-io/easegress/blob/main/pkg/filters/validator/validator.go) to inject a minimal response containing only a status code and error tags into the context.

```go
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`](https://github.com/easegress-io/easegress/blob/main/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.

```go
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`](https://github.com/easegress-io/easegress/blob/main/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.

```go
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:

```yaml
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:

```yaml
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.

```yaml
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`](https://github.com/easegress-io/easegress/blob/main/pkg/object/aigatewaycontroller/protocol/openai.go).

```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:

```yaml
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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/pkg/object/aigatewaycontroller/providers/base.go) automatically extracts provider errors into the `ErrorResponse` struct defined in [`pkg/object/aigatewaycontroller/protocol/openai.go`](https://github.com/easegress-io/easegress/blob/main/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.