Configuration: JSON error responses

This page documents the json_errors directive for generating structured JSON error responses instead of HTML. This is useful for RESTful API endpoints where clients expect machine-readable error bodies.

Directives

JSON errors

  • json_errors <enabled: bool> (http-jsonerror)
    • When true, HTTP error responses (4xx, 5xx) are returned with a JSON body instead of an HTML error page. Default: false

Block options

OptionArgumentsDescriptionDefault
format"problem" | "simple"Output format. "problem" uses RFC 9457 Problem Details (application/problem+json); "simple" uses plain JSON (application/json)."problem"
type_uri<string>URI for the type field in RFC 9457 format. The {status} placeholder is replaced with the HTTP status code."about:blank"
trace_id<bool>Include the request’s trace ID in the response when available.true

Configuration example:

example.com {
    json_errors
}

RFC 9457 Problem Details format

With format "problem" (default), responses use Content-Type: application/problem+json and follow the RFC 9457 structure:

example.com {
    json_errors {
        type_uri "https://api.example.com/errors/{status}"
    }
}

Example response for a 404 error:

{
  "type": "https://api.example.com/errors/404",
  "title": "Not Found",
  "status": 404,
  "detail": "The requested resource wasn't found.",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}

Simple JSON format

With format "simple", responses use Content-Type: application/json with a minimal structure:

example.com {
    json_errors {
        format "simple"
    }
}

Example response:

{
  "error": "Not Found",
  "status": 404,
  "detail": "The requested resource wasn't found.",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}

Scope to API paths

Use location blocks to enable JSON errors only for API endpoints:

example.com {
    location /api {
        json_errors {
            type_uri "https://api.example.com/errors/{status}"
        }
    }

    # Other paths get standard HTML error pages
}

Scoping

The json_errors directive can be placed at different configuration levels:

  • Host level — applies to all requests for that host
  • location block — applies only to requests matching that path prefix
  • if / if_not blocks — applies conditionally based on a matcher
example.com {
    # All errors are JSON for this host
    json_errors

    match BLOG {
        request.uri.path ~ "^/blog($|/)"
    }
    
    if BLOG {
        # Override: HTML error pages for the blog
        json_errors false
    }
}

Interaction with error pages

When json_errors is enabled, the JSON error stage runs before the error_page stage (which serves custom HTML error pages). This means:

  • JSON errors take precedence over error_page file-based error pages
  • The built-in HTML error page fallback is never reached when JSON errors are enabled
  • To use both HTML and JSON error pages for different paths, use location blocks

Observability

Trace spans

The stage sets the following attributes on its ferron.stage.json_error span:

AttributeTypeDescription
ferron.json_error.formatstringOutput format ("problem" or "simple")
ferron.json_error.status_codei64HTTP status code of the error response