# Error Handling Rfc9457

> RFC 9457 Problem Details for standardized HTTP API error responses. Use when implementing problem details format, structured API errors, error registries, or migrating from RFC 7807.

- Skill: `majiayu000/error-handling-rfc9457` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add majiayu000/error-handling-rfc9457`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/error-handling-rfc9457/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/error-handling-rfc9457

---


# RFC 9457 Problem Details

Standardize API error responses with machine-readable problem details.

## RFC 9457 vs RFC 7807

| Feature | RFC 7807 (Old) | RFC 9457 (Current) |
|---------|----------------|---------------------|
| Status | Obsolete | Active Standard |
| Multiple problems | Not specified | Explicitly supported |
| Error registry | No | Yes (IANA registry) |
| Extension fields | Implicit | Explicitly allowed |

## Problem Details Schema

```python
from pydantic import BaseModel, Field, HttpUrl
from typing import Any

class ProblemDetail(BaseModel):
    """RFC 9457 Problem Details for HTTP APIs."""

    type: HttpUrl = Field(
        default="about:blank",
        description="URI identifying the problem type"
    )
    title: str = Field(
        description="Short, human-readable summary"
    )
    status: int = Field(
        ge=400, le=599,
        description="HTTP status code"
    )
    detail: str | None = Field(
        default=None,
        description="Human-readable explanation specific to this occurrence"
    )
    instance: str | None = Field(
        default=None,
        description="URI reference identifying the specific occurrence"
    )

    model_config = {"extra": "allow"}  # Allow extension fields
```

## FastAPI Integration

### Exception Classes

```python
from fastapi import HTTPException
from typing import Any

class ProblemException(HTTPException):
    """Base exception for RFC 9457 problem details."""

    def __init__(
        self,
        status_code: int,
        problem_type: str,
        title: str,
        detail: str | None = None,
        instance: str | None = None,
        **extensions: Any,
    ):
        self.problem_type = problem_type
        self.title = title
        self.detail = detail
        self.instance = instance
        self.extensions = extensions
        super().__init__(status_code=status_code, detail=detail)

    def to_problem_detail(self) -> dict[str, Any]:
        result = {
            "type": self.problem_type,
            "title": self.title,
            "status": self.status_code,
        }
        if self.detail:
            result["detail"] = self.detail
        if self.instance:
            result["instance"] = self.instance
        result.update(self.extensions)
        return result
```

### Specific Problem Types

```python
class ValidationProblem(ProblemException):
    def __init__(self, errors: list[dict], instance: str | None = None):
        super().__init__(
            status_code=422,
            problem_type="https://api.example.com/problems/validation-error",
            title="Validation Error",
            detail="One or more fields failed validation",
            instance=instance,
            errors=errors,  # Extension field
        )

class NotFoundProblem(ProblemException):
    def __init__(self, resource: str, resource_id: str, instance: str | None = None):
        super().__init__(
            status_code=404,
            problem_type="https://api.example.com/problems/resource-not-found",
            title="Resource Not Found",
            detail=f"{resource} with ID '{resource_id}' was not found",
            instance=instance,
            resource=resource,
            resource_id=resource_id,
        )

class RateLimitProblem(ProblemException):
    def __init__(self, retry_after: int, instance: str | None = None):
        super().__init__(
            status_code=429,
            problem_type="https://api.example.com/problems/rate-limit-exceeded",
            title="Too Many Requests",
            detail="Rate limit exceeded. Please retry later.",
            instance=instance,
            retry_after=retry_after,
        )
```

### Exception Handler

```python
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError

app = FastAPI()

@app.exception_handler(ProblemException)
async def problem_exception_handler(request: Request, exc: ProblemException):
    return JSONResponse(
        status_code=exc.status_code,
        content=exc.to_problem_detail(),
        media_type="application/problem+json",
    )

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    errors = [
        {"field": ".".join(str(loc) for loc in err["loc"]), "message": err["msg"]}
        for err in exc.errors()
    ]
    problem = ValidationProblem(errors=errors, instance=str(request.url))
    return JSONResponse(
        status_code=422,
        content=problem.to_problem_detail(),
        media_type="application/problem+json",
    )

@app.exception_handler(Exception)
async def generic_exception_handler(request: Request, exc: Exception):
    return JSONResponse(
        status_code=500,
        content={
            "type": "https://api.example.com/problems/internal-error",
            "title": "Internal Server Error",
            "status": 500,
            "detail": "An unexpected error occurred",
            "instance": str(request.url),
        },
        media_type="application/problem+json",
    )
```

## Usage in Endpoints

```python
@router.get("/api/v1/analyses/{analysis_id}")
async def get_analysis(
    analysis_id: str,
    request: Request,
    service: AnalysisService = Depends(get_analysis_service),
):
    analysis = await service.get_by_id(analysis_id)
    if not analysis:
        raise NotFoundProblem(
            resource="Analysis",
            resource_id=analysis_id,
            instance=str(request.url),
        )
    return analysis
```

## Response Examples

### 404 Not Found

```json
{
  "type": "https://api.example.com/problems/resource-not-found",
  "title": "Resource Not Found",
  "status": 404,
  "detail": "Analysis with ID 'abc123' was not found",
  "instance": "/api/v1/analyses/abc123",
  "resource": "Analysis",
  "resource_id": "abc123"
}
```

### 422 Validation Error

```json
{
  "type": "https://api.example.com/problems/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "One or more fields failed validation",
  "instance": "/api/v1/analyses",
  "errors": [
    {"field": "source_url", "message": "Invalid URL format"},
    {"field": "depth", "message": "Must be between 1 and 3"}
  ]
}
```

### 429 Rate Limited

```json
{
  "type": "https://api.example.com/problems/rate-limit-exceeded",
  "title": "Too Many Requests",
  "status": 429,
  "detail": "Rate limit exceeded. Please retry later.",
  "instance": "/api/v1/analyses",
  "retry_after": 60
}
```

## Error Type Registry

```python
# app/core/problem_types.py
PROBLEM_TYPES = {
    "validation-error": {
        "uri": "https://api.example.com/problems/validation-error",
        "title": "Validation Error",
        "status": 422,
    },
    "resource-not-found": {
        "uri": "https://api.example.com/problems/resource-not-found",
        "title": "Resource Not Found",
        "status": 404,
    },
    "rate-limit-exceeded": {
        "uri": "https://api.example.com/problems/rate-limit-exceeded",
        "title": "Too Many Requests",
        "status": 429,
    },
    "unauthorized": {
        "uri": "https://api.example.com/problems/unauthorized",
        "title": "Unauthorized",
        "status": 401,
    },
    "forbidden": {
        "uri": "https://api.example.com/problems/forbidden",
        "title": "Forbidden",
        "status": 403,
    },
    "conflict": {
        "uri": "https://api.example.com/problems/conflict",
        "title": "Conflict",
        "status": 409,
    },
    "internal-error": {
        "uri": "https://api.example.com/problems/internal-error",
        "title": "Internal Server Error",
        "status": 500,
    },
}
```

## Anti-Patterns (FORBIDDEN)

```python
# NEVER return plain text errors
return Response("Not found", status_code=404)

# NEVER use inconsistent error formats
return {"error": "Not found"}  # Different from other errors
return {"message": "Validation failed", "errors": [...]}

# NEVER expose internal details in production
return {"detail": str(exc), "traceback": traceback.format_exc()}

# NEVER use generic 500 for everything
except Exception:
    raise HTTPException(500, "Something went wrong")
```

## Key Decisions

| Decision | Recommendation |
|----------|----------------|
| Media type | `application/problem+json` |
| Type URI | Use your API domain + `/problems/` |
| Detail | Include only for user-actionable info |
| Extensions | Use for machine-readable context |
| Logging | Log problem types for monitoring |

## Related Skills

- `api-design-framework` - REST API patterns
- `observability-monitoring` - Error tracking
- `input-validation` - Validation patterns

## Capability Details

### problem-details
**Keywords:** problem details, RFC 9457, RFC 7807, structured error
**Solves:**
- How to standardize API error responses?
- What format for API errors?

### fastapi-errors
**Keywords:** fastapi exception, error handler, HTTPException
**Solves:**
- How to handle errors in FastAPI?
- Custom exception handlers

### error-registry
**Keywords:** error registry, problem types, error catalog
**Solves:**
- How to document all API errors?
- Error type management

