> ERROR CONTRACTS DEFINE THE MACHINE-READABLE STRUCTURE, HUMAN-READABLE MESSAGE, AND ACTIONABLE REMEDIATION FOR EVERY FAILURE MODE — CONSISTENT ERROR RESPONSE DESIGN LETS CLIENTS HANDLE ERRORS PROGRAMMATICALLY WITHOUT PARSING FREE-TEXT OR REVERSE-ENGINEERING FAILURE SEMANTICS.
Scanned 9/11/2026
Install to Claude Code
npx -y skills add Intense-Visions/harness-engineering --skill api-error-contracts --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Api Error Contracts?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/intense-visions-api-error-contracts-3d5e444e)More formats (shields.io, HTML) on the badges page.
# API Error Contracts
> ERROR CONTRACTS DEFINE THE MACHINE-READABLE STRUCTURE, HUMAN-READABLE MESSAGE, AND ACTIONABLE REMEDIATION FOR EVERY FAILURE MODE — CONSISTENT ERROR RESPONSE DESIGN LETS CLIENTS HANDLE ERRORS PROGRAMMATICALLY WITHOUT PARSING FREE-TEXT OR REVERSE-ENGINEERING FAILURE SEMANTICS.
## When to Use
- Designing the error response shape for a new API or service before writing any handlers
- Reviewing a PR that returns unstructured error strings or inconsistent error shapes across endpoints
- Establishing an API style guide section on error response standards for a team or organization
- Auditing an existing API whose clients report confusion about how to distinguish error categories
- Choosing between application-level error codes (e.g., `CARD_DECLINED`) and HTTP status codes for client routing
- Building SDKs or client libraries that need to surface typed, catchable error objects to callers
- Implementing error monitoring and alerting where machine-readable codes are required to classify alerts
- Documenting all possible error conditions for each endpoint in an OpenAPI specification
## Instructions
### Key Concepts
1. **Machine-readable error codes** — An application-level error code (`"code": "INSUFFICIENT_FUNDS"`) is distinct from the HTTP status code. It identifies the specific failure type within a category so clients can branch on it without parsing free-text messages. Example: two Stripe `402` responses may have `"code": "card_declined"` or `"code": "expired_card"` — the HTTP status routes to the payment-failure handler; the code selects the message shown to the user.
2. **Human-readable messages** — The `message` field is for developers reading logs or API explorer output, not for display in end-user interfaces. It should be complete and unambiguous: `"The card ending in 4242 was declined by the issuer"` rather than `"Card error"`. Avoid exposing internal implementation details, stack traces, or database error messages.
3. **Actionable remediation** — Every error response should answer: "What should the caller do next?" The `"detail"` field (per RFC 9457) or a dedicated `"suggestion"` field communicates the next step: `"Retry with a different payment method"`, `"Check that the field matches ISO 8601 format"`, or `"Contact support with reference ID abc-123"`. Errors without remediation guidance shift the debugging burden to the caller.
4. **Error taxonomy** — Group error codes into categories that map to HTTP status classes: authentication errors (`401`), authorization errors (`403`), validation errors (`422`), business-rule violations (`409`/`422`), and server faults (`500`). A taxonomy prevents code proliferation and makes documentation searchable. Publish the full taxonomy in API reference docs; include a `type` URI (per RFC 9457) so clients can link to the documentation for each error type.
5. **Consistent envelope structure** — Every error response from every endpoint must use the same JSON shape. Mixing `{ "error": "..." }`, `{ "message": "...", "errors": [...] }`, and `{ "code": ..., "description": ... }` across endpoints breaks SDK code generation and forces client-side shape detection. Choose one envelope (RFC 9457 Problem Details is the recommended standard) and enforce it at the framework/middleware level.
6. **Error reference IDs** — For server-side faults (`5xx`), include a unique `instance` or `traceId` field that correlates the response to a specific log entry. This enables support teams to locate the root cause without asking users to reproduce the issue. Example: `"instance": "/errors/7f3a-bc91-..."` or `"traceId": "abc-123-xyz"`.
### Worked Example
Stripe's error contract is one of the most studied in production APIs. It uses a consistent envelope across all failure modes:
**Payment declined (402 Payment Required):**
```http
POST /v1/charges
Authorization: Bearer sk_example_...
Content-Type: application/x-www-form-urlencoded
amount=2000¤cy=usd&source=tok_chargeDeclined
```
```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
{
"error": {
"type": "card_error",
"code": "card_declined",
"decline_code": "insufficient_funds",
"message": "Your card has insufficient funds.",
"param": "source",
"charge": "ch_3N..."
}
}
```
**Invalid API key (401 Unauthorized):**
```http
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "No such API key: sk_example_****abc.",
"doc_url": "https://stripe.com/docs/error-codes/api-key-invalid"
}
}
```
**Missing required parameter (400 Bad Request):**
```http
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"type": "invalid_request_error",
"code": "parameter_missing",
"message": "Missing required param: amount.",
"param": "amount",
"doc_url": "https://stripe.com/docs/error-codes/parameter-missing"
}
}
```
Stripe's taxonomy (`card_error`, `authentication_error`, `invalid_request_error`, `api_error`, `idempotency_error`) maps cleanly to HTTP status ranges. The `code` field gives a programmatic subcategory; `param` identifies the offending field; `doc_url` links to remediation. SDK clients switch on `error.type` for top-level routing and `error.code` for specific handling — without any free-text parsing.
### Anti-Patterns
1. **Free-text error strings only.** `{ "error": "Something went wrong" }` or `{ "message": "Invalid input" }` forces clients to parse English prose to determine the error type. Localization, rewording, or phrasing changes in the message silently break clients that pattern-match on strings. Fix: always include a machine-readable `code` field alongside the human-readable `message`.
2. **Inconsistent envelope shape across endpoints.** When one endpoint returns `{ "error": { "message": "..." } }` and another returns `{ "errors": ["..."] }` and a third returns `{ "status": "error", "reason": "..." }`, client error handling requires per-endpoint special cases. Fix: enforce a single error shape at the middleware or gateway layer so every response is shaped identically before leaving the server.
3. **Leaking internal error details.** Including `"sqlState": "23000"`, `"stackTrace": "..."`, or `"internalMessage": "NullPointerException at line 42"` in error responses exposes implementation internals, aids attackers, and creates API surface that clients may start depending on. Fix: log internal details server-side and surface only a `traceId` for correlation. The public error contains only what is safe and useful for the caller.
4. **Omitting actionable remediation.** An error like `{ "code": "RATE_LIMITED" }` without a `Retry-After` header or a `detail` explaining when to retry is incomplete. The caller either retries immediately (worsening the rate-limit problem) or gives up unnecessarily. Fix: every error response should include what the caller should do next — retry timing, which parameter to fix, or where to get help.
## Details
### Error Code Naming Conventions
Error codes should use consistent casing (SCREAMING_SNAKE_CASE for application codes is common; `snake_case` is used by Stripe and GitHub). Codes must be stable across API versions — changing `CARD_DECLINED` to `PAYMENT_DECLINED` is a breaking change for any client that switches on the code. Prefix codes by domain when the taxonomy is large: `AUTH_TOKEN_EXPIRED`, `PAYMENT_CARD_DECLINED`, `VALIDATION_FIELD_REQUIRED`.
### Error Documentation Requirements
Every published error code should be documented with: the HTTP status code it accompanies, a description of when it occurs, the fields present in the response for this code, and recommended client action. This documentation is the contract — treat removals or renames as breaking changes.
### Real-World Case Study: Twilio Error Contracts
Twilio maintains a published error dictionary at `twilio.com/docs/api/errors` with over 600 documented error codes. Each code has a dedicated page with: description, possible causes, and suggested resolution steps. When Twilio's REST API returns an error, it includes `"code": 21211` (for example) alongside the HTTP `400` status. Clients look up the code in documentation or switch on it directly. Twilio's developer surveys show that APIs with published error taxonomies reduce average debugging time by 40-60% compared to APIs that return only HTTP status codes and free-text messages. The combination of stable machine-readable codes and linked documentation is the highest-leverage investment in API error design.
## Source
- [Creating Good API Errors in REST, GraphQL, and gRPC — APIs You Won't Hate](https://apisyouwonthate.com/blog/creating-good-api-errors-in-rest-graphql-and-grpc)
- [RFC 9457 — Problem Details for HTTP APIs](https://rfc-editor.org/rfc/rfc9457)
- [Stripe API Error Reference](https://stripe.com/docs/api/errors)
- [Twilio Error and Warning Dictionary](https://www.twilio.com/docs/api/errors)
- [Microsoft REST API Guidelines — Error Responses](https://github.com/microsoft/api-guidelines/blob/vNext/azure/Guidelines.md#error-responses)
## Process
1. Define the error envelope structure: choose RFC 9457 Problem Details or a documented custom shape, and enforce it at the framework level across all endpoints.
2. Create an error taxonomy document listing every application-level error code, its HTTP status, its description, and its recommended client action.
3. For each endpoint, document all possible error codes in the OpenAPI spec under the appropriate `4xx`/`5xx` response schemas.
4. Implement an error serialization middleware that maps internal exceptions to the canonical error envelope — never let raw exception types reach the serializer.
5. Run `harness validate` to confirm skill files are well-formed and related skills are correctly cross-referenced.
## Harness Integration
- **Type:** knowledge — this skill is a reference document, not a procedural workflow.
- **No tools or state** — consumed as context by other skills and agents.
- **related_skills:** api-problem-details-rfc, api-status-codes, api-validation-errors, api-bulk-operations
## Success Criteria
- Every error response across all endpoints uses the same JSON envelope structure.
- All error responses include a stable, machine-readable `code` field alongside the human-readable `message`.
- No error response exposes internal stack traces, SQL errors, or raw exception messages.
- Every `5xx` response includes a `traceId` or `instance` field for log correlation.
- The full error taxonomy is published in API documentation with remediation guidance for each code.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!