DEV Community

Preecha
Preecha

Posted on

What Is RFC 9457 and How Should APIs Return Errors?

TL;DR

RFC 9457, “Problem Details for HTTP APIs,” defines a standard format for API errors. It replaces custom error payloads with a consistent structure based on type, title, status, detail, and instance. Modern PetstoreAPI uses RFC 9457 for its error responses, including content negotiation and field-level validation details.

Try Apidog today

Introduction

When an API returns an error, the response often uses a custom format:

{"error": "Invalid email"}
Enter fullscreen mode Exit fullscreen mode
{"message": "Not found", "code": 404}
Enter fullscreen mode Exit fullscreen mode
{"success": false, "errors": ["Email required"]}
Enter fullscreen mode Exit fullscreen mode

Every custom format increases integration work. Clients need different parsing logic for each API, and there is no consistent way to display errors, log diagnostic details, or handle validation failures.

RFC 9457 solves this by defining a standard error format that clients can parse consistently. Instead of inventing a new structure, return a problem details object with a standard media type:

Content-Type: application/problem+json
Enter fullscreen mode Exit fullscreen mode

The old Swagger Petstore used custom error formats with no consistency. Modern PetstoreAPI implements RFC 9457 across its error responses, providing structured, machine-readable error details.

In this guide, you’ll learn how RFC 9457 works, how to implement it, and how to test your API for compliance.

The API Error Problem

Before RFC 9457, APIs commonly returned errors in several incompatible formats.

Common Error Format Variations

Format 1: Simple message

{
  "error": "User not found"
}
Enter fullscreen mode Exit fullscreen mode

Format 2: Code and message

{
  "code": "USER_NOT_FOUND",
  "message": "User not found"
}
Enter fullscreen mode Exit fullscreen mode

Format 3: Nested structure

{
  "success": false,
  "error": {
    "type": "NotFound",
    "message": "User not found"
  }
}
Enter fullscreen mode Exit fullscreen mode

Format 4: Array of errors

{
  "errors": [
    {
      "field": "email",
      "message": "Invalid email"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Problems with Custom Formats

Custom error formats create several problems:

  1. No consistency: Clients need custom parsing logic for each API.
  2. Missing information: Some formats omit error codes, details, or both.
  3. Limited machine readability: Clients cannot reliably process errors programmatically.
  4. Poor internationalization: Hardcoded messages are difficult to translate.
  5. No standard validation structure: APIs represent field-level errors differently.

What Is RFC 9457?

RFC 9457, published in July 2023, defines “Problem Details for HTTP APIs.” It is an IETF standard for structuring HTTP error responses.

Key Features

  • Standard media types: application/problem+json and application/problem+xml
  • Consistent structure: Errors use the same core fields
  • Machine-readable data: Clients can process errors programmatically
  • Extensibility: APIs can add custom fields without breaking the standard structure
  • HTTP integration: Problem details work with standard HTTP status codes

RFC 9457 vs. Custom Errors

A custom error might look like this:

{
  "error": "Email is required"
}
Enter fullscreen mode Exit fullscreen mode

An RFC 9457 response can provide more context:

{
  "type": "https://petstoreapi.com/errors/validation-error",
  "title": "Validation Error",
  "status": 400,
  "detail": "The request contains invalid data",
  "instance": "/pets",
  "errors": [
    {
      "field": "email",
      "message": "Email is required"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

This response includes:

  • A type URL for error documentation
  • A stable, human-readable title
  • The HTTP status code
  • A description of the specific failure
  • The request path associated with the error
  • Field-level validation details

RFC 9457 Structure Explained

RFC 9457 defines five standard fields and allows custom extensions.

Standard Fields

1. type

type is a URI reference that identifies the error type. Ideally, it points to human-readable documentation.

{
  "type": "https://petstoreapi.com/errors/validation-error"
}
Enter fullscreen mode Exit fullscreen mode

If omitted, type defaults to about:blank.

2. title

title is a short, human-readable summary of the error type. It should remain stable between occurrences of the same error type.

{
  "title": "Validation Error"
}
Enter fullscreen mode Exit fullscreen mode

3. status

status contains the HTTP status code associated with the problem.

{
  "status": 400
}
Enter fullscreen mode Exit fullscreen mode

The value should match the status code in the HTTP response.

4. detail

detail is a human-readable explanation specific to the current occurrence.

{
  "detail": "The email field must be a valid email address"
}
Enter fullscreen mode Exit fullscreen mode

5. instance

instance identifies the specific occurrence of the problem. It is often set to the request path.

{
  "instance": "/pets/019b4132-70aa-764f-b315-e2803d882a24"
}
Enter fullscreen mode Exit fullscreen mode

Custom Extensions

You can add fields for application-specific context while keeping the standard fields intact:

{
  "type": "https://petstoreapi.com/errors/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded the rate limit of 100 requests per minute",
  "instance": "/pets",
  "retryAfter": 42,
  "limit": 100,
  "remaining": 0,
  "resetAt": "2026-03-13T10:30:00Z"
}
Enter fullscreen mode Exit fullscreen mode

Common extension fields include:

  • errors for field-level validation failures
  • retryAfter for retry timing
  • traceId for correlating logs and requests
  • Rate-limit metadata such as limit, remaining, and resetAt

Implementing RFC 9457 in an API

A typical implementation should:

  1. Define a consistent problem details schema.
  2. Set Content-Type: application/problem+json for error responses.
  3. Map each error category to a stable type URI.
  4. Ensure the response status matches the HTTP status code.
  5. Add extension fields for validation or domain-specific details.
  6. Test both the payload and response headers.

A generic error response might look like this:

HTTP/1.1 404 Not Found
Content-Type: application/problem+json
Enter fullscreen mode Exit fullscreen mode
{
  "type": "https://api.example.com/errors/resource-not-found",
  "title": "Resource Not Found",
  "status": 404,
  "detail": "The requested resource does not exist",
  "instance": "/resources/invalid-id"
}
Enter fullscreen mode Exit fullscreen mode

How Modern PetstoreAPI Implements RFC 9457

Modern PetstoreAPI uses RFC 9457 for its error responses.

Example 1: Resource Not Found

GET /pets/invalid-id
Enter fullscreen mode Exit fullscreen mode
HTTP/1.1 404 Not Found
Content-Type: application/problem+json
Enter fullscreen mode Exit fullscreen mode
{
  "type": "https://docs.petstoreapi.com/errors/not-found",
  "title": "Resource Not Found",
  "status": 404,
  "detail": "The requested pet does not exist",
  "instance": "/pets/invalid-id"
}
Enter fullscreen mode Exit fullscreen mode

Example 2: Authentication Error

GET /pets
Enter fullscreen mode Exit fullscreen mode
HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
Enter fullscreen mode Exit fullscreen mode
{
  "type": "https://docs.petstoreapi.com/errors/unauthorized",
  "title": "Authentication Required",
  "status": 401,
  "detail": "Valid authentication credentials are required to access this resource",
  "instance": "/pets"
}
Enter fullscreen mode Exit fullscreen mode

Example 3: Rate Limit Exceeded

GET /pets
Enter fullscreen mode Exit fullscreen mode
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 60
Enter fullscreen mode Exit fullscreen mode
{
  "type": "https://docs.petstoreapi.com/errors/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded the rate limit of 100 requests per minute",
  "instance": "/pets",
  "limit": 100,
  "remaining": 0,
  "resetAt": "2026-03-13T10:31:00Z"
}
Enter fullscreen mode Exit fullscreen mode

See the Modern PetstoreAPI error handling documentation for all error types.

Handling Validation Errors with RFC 9457

Validation errors usually need more than a single message. Clients often need to know:

  • Which field failed
  • Why validation failed
  • Which machine-readable rule was violated
  • Which value was rejected

RFC 9457 allows this information through custom extension fields.

Modern PetstoreAPI Validation Format

POST /pets
Enter fullscreen mode Exit fullscreen mode
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Enter fullscreen mode Exit fullscreen mode
{
  "type": "https://docs.petstoreapi.com/errors/validation-error",
  "title": "Validation Error",
  "status": 400,
  "detail": "The request contains 2 validation errors",
  "instance": "/pets",
  "errors": [
    {
      "field": "name",
      "message": "Name is required",
      "code": "REQUIRED_FIELD"
    },
    {
      "field": "species",
      "message": "Species must be one of: DOG, CAT, BIRD, FISH, REPTILE, OTHER",
      "code": "INVALID_ENUM_VALUE",
      "rejectedValue": "DRAGON"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Validation Field Conventions

The errors array contains field-level validation details:

  • field: The JSON path to the invalid field
  • message: A human-readable explanation
  • code: A machine-readable validation code
  • rejectedValue: The value that failed validation, when appropriate

Clients can use this structure to:

  • Display field-level errors in forms
  • Highlight invalid fields
  • Show specific error messages
  • Handle validation failures programmatically

Testing Error Responses with Apidog

Apidog can help validate RFC 9457 response structures, headers, and status codes.

Test Case: Validate the Problem Details Structure

pm.test("Returns RFC 9457 error format", () => {
  const response = pm.response.json();

  pm.expect(response).to.have.property("type");
  pm.expect(response).to.have.property("title");
  pm.expect(response).to.have.property("status");

  pm.expect(response.status).to.equal(pm.response.code);

  pm.expect(pm.response.headers.get("Content-Type"))
    .to.include("application/problem+json");
});
Enter fullscreen mode Exit fullscreen mode

Test Case: Validate Field-Level Errors

pm.test("Validation errors include field details", () => {
  const response = pm.response.json();

  pm.expect(response).to.have.property("errors");
  pm.expect(response.errors).to.be.an("array");

  response.errors.forEach((error) => {
    pm.expect(error).to.have.property("field");
    pm.expect(error).to.have.property("message");
  });
});
Enter fullscreen mode Exit fullscreen mode

Test Case: Verify Error Type URLs

If your type values point to documentation endpoints, test that those URLs are accessible:

pm.test("Error type URL is accessible", async () => {
  const response = pm.response.json();
  const typeUrl = response.type;

  const docResponse = await pm.sendRequest(typeUrl);

  pm.expect(docResponse.code).to.equal(200);
});
Enter fullscreen mode Exit fullscreen mode

When testing, check all of the following:

  • The response uses application/problem+json
  • The HTTP status and status field match
  • Required problem details fields are present
  • Validation responses include field-level information
  • Error type URLs resolve to documentation when applicable

Migrating from Custom Error Formats

If your API already returns custom errors, migrate incrementally.

Step 1: Add the Problem Details Content Type

Return the RFC 9457 media type for problem responses:

Content-Type: application/problem+json
Enter fullscreen mode Exit fullscreen mode

Step 2: Map Existing Fields

For example, convert this custom response:

{
  "error": "USER_NOT_FOUND",
  "message": "User not found"
}
Enter fullscreen mode Exit fullscreen mode

Into an RFC 9457 response:

{
  "type": "https://api.example.com/errors/user-not-found",
  "title": "User Not Found",
  "status": 404,
  "detail": "User not found"
}
Enter fullscreen mode Exit fullscreen mode

A practical field mapping looks like this:

Custom field RFC 9457 field
error type or a custom code extension
message detail
HTTP response code status
Request identifier or path instance

Step 3: Support Both Formats During the Transition

Use content negotiation to support existing clients while introducing RFC 9457:

Accept: application/json
Enter fullscreen mode Exit fullscreen mode

Return the legacy format for clients that still require it.

Accept: application/problem+json
Enter fullscreen mode Exit fullscreen mode

Return the RFC 9457 format for migrated clients.

Document the transition clearly and test both representations.

Step 4: Deprecate the Custom Format

After clients have migrated, deprecate the legacy format and return RFC 9457 by default.

Conclusion

RFC 9457 provides a consistent, machine-readable format for HTTP API errors. It standardizes common fields such as type, title, status, detail, and instance while allowing extensions for validation and domain-specific data.

Modern PetstoreAPI demonstrates how to apply the standard across resource, authentication, rate-limit, and validation errors. A consistent response format makes it easier for clients to parse errors, display useful messages, and diagnose failures.

Use Apidog to test RFC 9457 compliance, validate error structures, verify content types, and confirm that response status codes match the status field.

FAQ

Is RFC 9457 required for REST APIs?

No. RFC 9457 is a recommended standard rather than a requirement. Using it makes APIs more consistent and easier for clients to integrate.

Can I use RFC 9457 with XML?

Yes. RFC 9457 defines both JSON and XML representations:

  • application/problem+json
  • application/problem+xml

Should I always include all five standard fields?

type, title, and status are required in the structure described here. detail and instance are optional but useful for providing more context.

Can I add custom fields to RFC 9457 responses?

Yes. RFC 9457 is extensible. You can add fields such as errors, retryAfter, or traceId without changing the standard fields.

How do I handle validation errors with RFC 9457?

Add a custom errors array containing field-level details. Each item can include the field path, human-readable message, machine-readable code, and rejected value.

What should the error type URL point to?

It should point to human-readable documentation that explains the error type, its possible causes, and how to resolve it.

Do I need to change HTTP status codes when using RFC 9457?

No. RFC 9457 works with standard HTTP status codes. The response’s status field should match the HTTP status code.

How do I test RFC 9457 compliance?

Validate the response structure, required fields, content type, status-code consistency, and any custom validation fields. Apidog can be used to automate these checks.

Top comments (0)