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
prepareErrorResponseinpkg/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
ErrorResponsestruct inpkg/object/aigatewaycontroller/protocol/openai.goenables 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →