api-error-handling
Scannednpx machina-cli add skill secondsky/claude-skills/api-error-handling --openclawAPI Error Handling
Implement robust error handling with standardized responses and proper logging.
Standard Error Response Format
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"status": 400,
"requestId": "req_abc123",
"timestamp": "2025-01-15T10:30:00Z",
"details": [
{ "field": "email", "message": "Invalid email format" }
]
}
}
Error Class (Node.js)
class ApiError extends Error {
constructor(code, message, status = 500, details = null) {
super(message);
this.code = code;
this.status = status;
this.details = details;
}
static badRequest(message, details) {
return new ApiError('BAD_REQUEST', message, 400, details);
}
static notFound(resource) {
return new ApiError('NOT_FOUND', `${resource} not found`, 404);
}
static unauthorized() {
return new ApiError('UNAUTHORIZED', 'Authentication required', 401);
}
}
// Global error handler
app.use((err, req, res, next) => {
const status = err.status || 500;
const response = {
error: {
code: err.code || 'INTERNAL_ERROR',
message: status === 500 ? 'Internal server error' : err.message,
status,
requestId: req.id
}
};
if (err.details) response.error.details = err.details;
if (status >= 500) logger.error(err);
res.status(status).json(response);
});
Circuit Breaker Pattern
class CircuitBreaker {
constructor(threshold = 5, timeout = 30000) {
this.failures = 0;
this.threshold = threshold;
this.timeout = timeout;
this.state = 'CLOSED';
}
async call(fn) {
if (this.state === 'OPEN') throw new Error('Circuit open');
try {
const result = await fn();
this.failures = 0;
return result;
} catch (err) {
this.failures++;
if (this.failures >= this.threshold) {
this.state = 'OPEN';
setTimeout(() => this.state = 'HALF_OPEN', this.timeout);
}
throw err;
}
}
}
Additional Implementations
See references/python-flask.md for:
- Python Flask error handling with custom exceptions
- Circuit breaker with automatic recovery
- Retry with exponential backoff
- Sentry integration
Best Practices
- Use consistent error format across all endpoints
- Include request IDs for traceability
- Log errors at appropriate severity levels
- Never expose stack traces to clients
- Distinguish client errors (4xx) from server errors (5xx)
- Provide actionable error messages
Source
git clone https://github.com/secondsky/claude-skills/blob/main/plugins/api-error-handling/skills/api-error-handling/SKILL.mdView on GitHub Overview
Implements a standardized error response format for APIs, with a reusable ApiError class and a global error handler. This approach improves traceability, user-friendly messaging, and consistent logging across endpoints.
How This Skill Works
Developers create ApiError instances (or use helpers like badRequest, notFound, unauthorized) to represent failures with code, message, status, and optional details. The global error handler then formats a consistent payload (including requestId and timestamp) and sends it with the appropriate HTTP status, while logging as needed. The included circuit breaker example demonstrates guarding risky calls to prevent cascading failures.
When to Use It
- Building production APIs that require a consistent, client-friendly error payload
- Implementing centralized logging and request tracing with a unique requestId
- Guarding external/downstream calls with a circuit breaker pattern
- Delivering actionable error messages without leaking internals
- Integrating with error monitoring tools and logging pipelines
Quick Start
- Step 1: Create ApiError class with helpers (badRequest, notFound, unauthorized)
- Step 2: Add a global error-handling middleware that formats and returns the error payload
- Step 3: Wrap risky operations with a CircuitBreaker and log using a requestId
Best Practices
- Use a consistent error format across all endpoints
- Include a requestId for end-to-end traceability
- Log errors at appropriate severity levels (info/warning for 4xx, error for 5xx)
- Never expose stack traces or internal details to clients
- Differentiate 4xx (client) from 5xx (server) errors and tailor messages
Example Use Cases
- Return 400 with a detailed invalid parameter list using ApiError.badRequest with details
- Return 404 when a resource is not found using ApiError.notFound('Resource')
- Return 401 when authentication is missing using ApiError.unauthorized()
- Centralized global error handler includes requestId and standardized payload
- Wrap flaky external calls with a CircuitBreaker to avoid cascading failures