Automatically applies when writing error handling in APIs and tools. Ensures errors are returned as structured JSON with error, request_id, and timestamp (not plain strings).
Scanned 9/2/2026
Install to Claude Code
npx -y skills add majiayu000/claude-skill-registry --skill structured-errors-ricardoroche-ricardos-claude-code-2 --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Structured Errors Ricardoroche Ricardos Claude Code 2?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/majiayu000-structured-errors-ricardoroche-ricardos-claude-cod)More formats (shields.io, HTML) on the badges page.
---
name: structured-errors
description: Automatically applies when writing error handling in APIs and tools. Ensures errors are returned as structured JSON with error, request_id, and timestamp (not plain strings).
---
# Structured Error Response Enforcer
When writing error handling in API endpoints, tools, or services, always return structured JSON errors.
## ✅ Correct Pattern
```python
import uuid
from datetime import datetime
import json
def create_error_response(
error_message: str,
status_code: int = 500,
details: dict = None
) -> dict:
"""Create structured error response."""
response = {
"error": error_message,
"request_id": str(uuid.uuid4()),
"timestamp": datetime.now().isoformat(),
"status_code": status_code
}
if details:
response["details"] = details
return response
# In API endpoint
@app.get("/users/{user_id}")
async def get_user(user_id: str):
if not user_id:
raise HTTPException(
status_code=400,
detail=create_error_response(
"User ID is required",
status_code=400
)
)
try:
user = await fetch_user(user_id)
return user
except UserNotFoundError:
raise HTTPException(
status_code=404,
detail=create_error_response(
"User not found",
status_code=404,
details={"user_id": user_id}
)
)
# In tool function
def process_data(data: str) -> str:
if not data:
return json.dumps(create_error_response(
"Data is required",
status_code=400
))
try:
result = parse_data(data)
return json.dumps({"result": result})
except Exception as e:
return json.dumps(create_error_response(
"Failed to process data",
status_code=500,
details={"error_type": type(e).__name__}
))
```
## ❌ Incorrect Pattern
```python
# ❌ Plain string
if not user_id:
return "Error: user ID is required"
# ❌ Exposing sensitive data
except httpx.HTTPStatusError as e:
return f"Error: {e.response.text}" # ❌ Leaks API response
# ❌ No request ID for tracing
return {"error": "Something went wrong"}
# ❌ Inconsistent error format
return "Error: failed" # Sometimes string
return {"message": "failed"} # Sometimes object
```
## Required Fields
**All error responses must include:**
1. **error** (string) - Human-readable error message
2. **request_id** (uuid) - For tracing/debugging
3. **timestamp** (ISO string) - When error occurred
4. **status_code** (int) - HTTP status code
**Optional but recommended:**
5. **details** (object) - Additional context (safe data only)
6. **error_code** (string) - Application-specific error code
7. **field** (string) - Which field caused the error (validation)
## Custom Exception Classes
```python
class APIError(Exception):
"""Base exception for API errors."""
def __init__(self, message: str, status_code: int = 500, details: dict = None):
self.message = message
self.status_code = status_code
self.details = details or {}
self.request_id = str(uuid.uuid4())
self.timestamp = datetime.now().isoformat()
super().__init__(self.message)
def to_dict(self) -> dict:
"""Convert to structured error response."""
return {
"error": self.message,
"status_code": self.status_code,
"request_id": self.request_id,
"timestamp": self.timestamp,
"details": self.details
}
class ValidationError(APIError):
"""Validation error."""
def __init__(self, message: str, field: str = None):
details = {"field": field} if field else {}
super().__init__(message, status_code=400, details=details)
class NotFoundError(APIError):
"""Resource not found."""
def __init__(self, resource: str, resource_id: str):
super().__init__(
f"{resource} not found",
status_code=404,
details={"resource": resource, "id": resource_id}
)
# Usage
try:
user = await get_user(user_id)
except UserNotFoundError:
raise NotFoundError("User", user_id)
```
## FastAPI Integration
```python
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(APIError)
async def api_error_handler(request: Request, exc: APIError):
"""Global exception handler for APIError."""
return JSONResponse(
status_code=exc.status_code,
content=exc.to_dict()
)
@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception):
"""Catch-all for unexpected errors."""
error_response = create_error_response(
"Internal server error",
status_code=500,
details={"type": type(exc).__name__}
)
# Log full error but don't expose to client
logger.error(f"Unexpected error: {exc}", exc_info=True)
return JSONResponse(status_code=500, content=error_response)
```
## Security Note
**Never include in errors:**
- Raw API response text
- Stack traces (log them, don't return them)
- Internal IDs or tokens
- Database query details
- Full exception messages from external APIs
- Authentication credentials
- File paths or system information
**Safe to include:**
- User-facing error messages
- Validation field names
- Request IDs for support
- Status codes
- Generic error types
## Logging Errors
```python
import logging
logger = logging.getLogger(__name__)
def handle_error(error: Exception, context: dict = None) -> dict:
"""Handle error with proper logging and structured response."""
request_id = str(uuid.uuid4())
# Log with context
logger.error(
f"Error occurred | request_id={request_id} | "
f"error={type(error).__name__}",
extra=context,
exc_info=True
)
# Return safe error response
return create_error_response(
"An error occurred processing your request",
status_code=500,
details={"request_id": request_id}
)
```
## ❌ Anti-Patterns
```python
# ❌ Leaking internal errors
return {"error": str(exception)}
# ❌ Inconsistent format across endpoints
def endpoint1(): return "Error"
def endpoint2(): return {"error": "Error"}
# ❌ No context for debugging
return {"error": "Failed"}
# ❌ Returning 200 with error in body
return {"success": False, "error": "..."} # Should use proper status code
# ❌ Too much information
return {
"error": f"Database query failed: {full_sql_query}",
"stacktrace": traceback.format_exc()
}
```
## Best Practices Checklist
- ✅ Use consistent error structure across application
- ✅ Include request_id for tracing
- ✅ Include timestamp for debugging
- ✅ Use proper HTTP status codes
- ✅ Create custom exception classes for common errors
- ✅ Add global exception handlers
- ✅ Log full error details (with context)
- ✅ Return safe, user-friendly messages
- ✅ Never expose sensitive data in errors
- ✅ Document error responses in API docs
## Auto-Apply
When you write error handling:
1. Create helper `create_error_response()`
2. Use it for all error returns
3. Include request_id and timestamp
4. Remove any sensitive data
5. Use proper status codes
## Related Skills
- docstring-format - Document Raises section
- pii-redaction - Redact PII in error logs
- pydantic-models - For error response models
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!