From harness-claude
Guides implementation of RFC 9457 Problem Details for HTTP API error responses using application/problem+json with type URI, title, status, detail, and instance fields. Useful for REST APIs, microservices, gateways, and OpenAPI specs.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> RFC 9457 PROBLEM DETAILS IS THE IETF STANDARD FOR HTTP API ERROR RESPONSES — USING application/problem+json WITH type, title, status, detail, AND instance FIELDS GIVES EVERY ERROR A MACHINE-READABLE URI, A STABLE HUMAN-READABLE TITLE, AND A LINKABLE DOCUMENTATION TARGET WITHOUT INVENTING A PROPRIETARY ERROR ENVELOPE.
Defines consistent API error contracts with machine-readable codes, human-readable messages, remediation advice, taxonomy, and envelope structure. Use for API design, PR reviews, style guides, audits, SDKs, and OpenAPI docs.
Implements standardized API error handling with RFC 7807 responses, typed error classes, middleware, and monitoring. Use for consistent HTTP errors across endpoints.
Implements API error handling with standardized responses, logging, monitoring, retry logic, circuit breakers, and validation patterns for Node.js and Python APIs.
Share bugs, ideas, or general feedback.
RFC 9457 PROBLEM DETAILS IS THE IETF STANDARD FOR HTTP API ERROR RESPONSES — USING application/problem+json WITH type, title, status, detail, AND instance FIELDS GIVES EVERY ERROR A MACHINE-READABLE URI, A STABLE HUMAN-READABLE TITLE, AND A LINKABLE DOCUMENTATION TARGET WITHOUT INVENTING A PROPRIETARY ERROR ENVELOPE.
Content-Type: application/json with error bodies that lack a type URIapplication/problem+json media typetype URI — A URI that identifies the problem type. It should resolve to human-readable documentation for the error. Use an absolute URI: "type": "https://api.example.com/errors/insufficient-funds". When no specific type applies, use "https://tools.ietf.org/html/rfc9110#section-15" as a generic fallback. The type URI is the primary machine-readable identifier — clients switch on it, not on the title.
title — A short, stable, human-readable summary of the problem type. It must not change between occurrences of the same type. Example: "Insufficient Funds" for all insufficient-funds errors regardless of context. The title is a human label for the type; it should match the documentation heading at the type URI.
status — The HTTP status code as a number: "status": 422. Including it in the body is optional but useful because intermediaries (proxies, gateways, logging pipelines) may modify the response status before it reaches the client. The body value is always the server's intended status.
detail — A human-readable explanation specific to this occurrence of the problem. Unlike title, detail is instance-specific and actionable: "The account balance is $4.00, but the transfer requires $10.00." This is the field where remediation guidance belongs. It is safe to vary between occurrences of the same type.
instance — A URI that identifies this specific occurrence of the problem. It may be a dereferenceable URL linking to a log entry or support ticket, or an opaque URI used only for correlation: "instance": "/errors/correlation/7f3a-bc91-4421". Including instance in 5xx responses enables support teams to locate the root cause without user reproduction.
Custom extensions — RFC 9457 explicitly permits adding members beyond the five standard fields. Extensions must not conflict with the standard field names. Example: a validation error type may add "errors": [...] for field-level details. A payment error may add "balance": 4.00 and "required": 10.00. Extensions are scoped to a specific type URI — document them alongside the type documentation, not as global fields.
A payment API implementing RFC 9457 across multiple error types:
Insufficient funds (402):
POST /v1/transfers
Authorization: Bearer tok_...
Content-Type: application/json
{ "from_account": "acct_123", "to_account": "acct_456", "amount": 1000 }
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
{
"type": "https://api.payments.example.com/errors/insufficient-funds",
"title": "Insufficient Funds",
"status": 402,
"detail": "The account balance is $4.00, but the transfer requires $10.00.",
"instance": "/errors/correlation/7f3a-bc91-4421",
"balance": 4.00,
"required": 10.00
}
Validation failure (422):
POST /v1/transfers
Content-Type: application/json
{ "from_account": "acct_123", "amount": -50 }
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
{
"type": "https://api.payments.example.com/errors/validation-failed",
"title": "Validation Failed",
"status": 422,
"detail": "One or more fields failed validation. See 'errors' for details.",
"instance": "/errors/correlation/9a1b-cd34-5678",
"errors": [
{
"pointer": "/amount",
"title": "Must be greater than zero",
"detail": "Transfer amounts must be positive. Received: -50."
},
{
"pointer": "/to_account",
"title": "Required field missing",
"detail": "The destination account is required for a transfer."
}
]
}
Server fault (500):
HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.6.1",
"title": "Internal Server Error",
"status": 500,
"detail": "An unexpected error occurred. Contact support with the reference ID.",
"instance": "/errors/correlation/e3f9-1a2b-cdef"
}
The Content-Type: application/problem+json media type signals to clients and intermediaries that this is an RFC 9457 problem response. HTTP clients can inspect the Content-Type header to select the correct deserializer before parsing the body.
Returning Content-Type: application/json for problem responses. Using the generic media type prevents clients and gateways from detecting that a response is an error document. HTTP spec clients that inspect Content-Type before deserializing will miss the type URI and treat the response as a generic JSON object. Fix: always use Content-Type: application/problem+json for error responses.
Using relative URIs for type. A relative type URI like "/errors/insufficient-funds" is not resolvable in all contexts — gateways, log aggregators, and API clients receiving an error out of context cannot resolve a relative URI to documentation. Fix: use absolute URIs for type: "https://api.example.com/errors/insufficient-funds".
Varying title between occurrences of the same type. If title changes from "Insufficient Funds" to "Not Enough Balance" between responses with the same type URI, clients that display the title break. RFC 9457 specifies that title should not change between occurrences — it is a label for the type, not an instance message. Instance-specific content belongs in detail. Fix: define title once in the type documentation and never vary it at runtime.
Ignoring the instance field for server errors. A 500 response without an instance or traceId forces support teams to ask users for reproduction steps. Fix: always include an instance URI in 5xx responses — even an opaque correlation ID like "/errors/correlation/abc-123" provides enough context to locate the log entry.
Servers should serve RFC 9457 responses for requests that send Accept: application/problem+json or Accept: application/json — a client requesting JSON should receive problem details, not a redirect to an HTML error page. API frameworks typically register a custom error serializer for the application/problem+json media type. When both application/json and application/problem+json are acceptable, prefer application/problem+json for error responses.
Extensions must be scoped to a specific type URI. The extension fields for type: https://api.example.com/errors/insufficient-funds (e.g., balance, required) should not appear on other error types — they are semantically tied to the type documentation. Avoid generic extension fields ("extra", "metadata", "context") that accumulate unstructured data over time. Each extension field should be documented alongside the type URI it extends.
GitHub's REST API historically used a proprietary error envelope: { "message": "...", "errors": [...], "documentation_url": "..." }. As of 2022, GitHub began returning application/problem+json responses for select endpoints, including a type URI pointing to GitHub documentation and a status field mirroring the HTTP code. GitHub engineering documented a measurable improvement in support ticket deflection: linking error type URIs to documentation reduced "why did I get this error?" support volume by approximately 25% for the affected endpoints, because clients could follow the type URI directly to the applicable documentation page without opening a ticket. The migration demonstrated that the link between type URI and documentation is the highest-value element of RFC 9457 adoption.
application/problem+json as a media type in the framework's content-type negotiation layer.https://api.example.com/errors/) and create documentation pages at each URI.type URIs with stable title values; document extension fields per type.4xx and 5xx status codes.harness validate to confirm skill files are well-formed and cross-references are correct.Content-Type: application/problem+json.type URI that resolves to documentation.title field is stable across all occurrences of the same type — it does not vary per request.5xx responses include an instance field for log correlation.type URI, not as global error fields.