Cuihua Error Handler
v1.0.0π‘οΈ AI-powered error handling assistant that transforms fragile code into resilient systems. Automatically generate comprehensive error handling, recovery st...
Like a lobster shell, security has layers β review code before you run it.
Runtime requirements
cuihua-error-handler - Bulletproof Your Code π‘οΈ
Turn fragile code into production-ready, resilient systems.
An intelligent error handling assistant that automatically:
- π Detects missing error handling
- β¨ Generates comprehensive try/catch blocks
- π Implements recovery strategies (retry, fallback, circuit breaker)
- π Reports error handling coverage
- π‘οΈ Prevents silent failures and crashes
π― Why cuihua-error-handler?
The harsh reality:
- β 80% of production issues come from poor error handling
- β Silent failures waste hours of debugging
- β Unhandled rejections crash Node.js servers
- β Generic try/catch blocks hide the real problems
cuihua-error-handler fixes all of this.
π Quick Start
Analyze error handling
Tell your OpenClaw agent:
"Check error handling coverage in src/"
The agent will:
- Scan all async functions
- Detect missing try/catch blocks
- Identify swallowed errors
- Report error handling coverage
Add error handling
"Add error handling to getUserById in api/users.js"
The agent will:
- Analyze failure points
- Generate specific error types
- Add retry logic for network errors
- Add fallback for missing data
- Add structured logging
Generate recovery strategies
"Add circuit breaker to payment service"
The agent will:
- Implement circuit breaker pattern
- Add failure rate monitoring
- Generate fallback responses
- Add automatic recovery
π¨ Features
1. Smart Error Detection π
Automatically finds missing error handling:
// β BEFORE - Fragile code
async function getUserById(id) {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
// π DETECTED ISSUES:
// - No error handling for network failures
// - No handling for non-200 responses
// - No handling for invalid JSON
// - No logging for debugging
2. Comprehensive Error Handling β¨
Generates production-ready error handling:
// β
AFTER - Bulletproof code
class UserServiceError extends Error {
constructor(message, options = {}) {
super(message);
this.name = 'UserServiceError';
this.statusCode = options.statusCode;
this.originalError = options.cause;
}
}
async function getUserById(id) {
try {
// Validation
if (!id || typeof id !== 'string') {
throw new UserServiceError('Invalid user ID', { statusCode: 400 });
}
// Network request with timeout
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
const res = await fetch(`/api/users/${id}`, {
signal: controller.signal
});
clearTimeout(timeout);
// HTTP error handling
if (!res.ok) {
if (res.status === 404) {
throw new UserServiceError(`User ${id} not found`, { statusCode: 404 });
}
if (res.status >= 500) {
throw new UserServiceError('Server error, please retry', { statusCode: 502 });
}
throw new UserServiceError(`HTTP ${res.status}`, { statusCode: res.status });
}
// JSON parsing with error handling
let data;
try {
data = await res.json();
} catch (parseError) {
throw new UserServiceError('Invalid response format', {
statusCode: 502,
cause: parseError
});
}
return data;
} catch (error) {
// Network errors (timeout, connection refused)
if (error.name === 'AbortError') {
logger.error('getUserById timeout', { id, timeout: 5000 });
throw new UserServiceError('Request timeout', {
statusCode: 504,
cause: error
});
}
if (error.message.includes('fetch failed')) {
logger.error('getUserById network error', { id, error: error.message });
throw new UserServiceError('Network error', {
statusCode: 503,
cause: error
});
}
// Re-throw UserServiceError
if (error instanceof UserServiceError) {
logger.error('getUserById failed', { id, error: error.message });
throw error;
}
// Unexpected errors
logger.error('getUserById unexpected error', { id, error });
throw new UserServiceError('Internal error', {
statusCode: 500,
cause: error
});
}
}
3. Retry Strategies π
Smart retry with exponential backoff:
async function retryWithBackoff(fn, options = {}) {
const {
maxRetries = 3,
initialDelay = 1000,
maxDelay = 10000,
backoffFactor = 2,
shouldRetry = (error) => true
} = options;
let lastError;
let delay = initialDelay;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
// Check if we should retry
if (attempt === maxRetries || !shouldRetry(error)) {
throw error;
}
// Wait before retry
logger.warn(`Retry attempt ${attempt + 1}/${maxRetries} after ${delay}ms`, {
error: error.message
});
await new Promise(resolve => setTimeout(resolve, delay));
// Exponential backoff
delay = Math.min(delay * backoffFactor, maxDelay);
}
}
throw lastError;
}
// Usage
async function fetchUserWithRetry(id) {
return retryWithBackoff(
() => getUserById(id),
{
maxRetries: 3,
shouldRetry: (error) => {
// Retry on network errors and 5xx
return error.statusCode >= 500 || error.name === 'NetworkError';
}
}
);
}
4. Circuit Breaker Pattern β‘
Prevent cascading failures:
class CircuitBreaker {
constructor(fn, options = {}) {
this.fn = fn;
this.failureThreshold = options.failureThreshold || 5;
this.resetTimeout = options.resetTimeout || 60000;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
this.failureCount = 0;
this.nextAttempt = Date.now();
}
async execute(...args) {
if (this.state === 'OPEN') {
if (Date.now() < this.nextAttempt) {
throw new Error('Circuit breaker is OPEN');
}
// Try to recover
this.state = 'HALF_OPEN';
}
try {
const result = await this.fn(...args);
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failureCount = 0;
if (this.state === 'HALF_OPEN') {
this.state = 'CLOSED';
logger.info('Circuit breaker recovered');
}
}
onFailure() {
this.failureCount++;
if (this.failureCount >= this.failureThreshold) {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.resetTimeout;
logger.error('Circuit breaker opened', {
failureCount: this.failureCount,
resetTimeout: this.resetTimeout
});
}
}
}
// Usage
const getUserBreaker = new CircuitBreaker(getUserById, {
failureThreshold: 5,
resetTimeout: 60000
});
async function fetchUserSafely(id) {
try {
return await getUserBreaker.execute(id);
} catch (error) {
if (error.message === 'Circuit breaker is OPEN') {
// Return cached data or default
return getCachedUser(id) || { id, name: 'Unknown', error: true };
}
throw error;
}
}
5. Graceful Degradation π―
Fallback to cached/default data:
async function getUserWithFallback(id) {
try {
// Try primary source
return await getUserById(id);
} catch (error) {
logger.warn('Primary source failed, trying fallback', { id, error: error.message });
try {
// Try cache
const cached = await cache.get(`user:${id}`);
if (cached) {
logger.info('Returned cached user', { id });
return { ...cached, _cached: true };
}
} catch (cacheError) {
logger.error('Cache also failed', { id, error: cacheError.message });
}
// Return default user
logger.warn('Returning default user', { id });
return {
id,
name: 'Guest User',
_default: true,
_error: error.message
};
}
}
6. Error Coverage Analysis π
Comprehensive coverage reporting:
π‘οΈ Error Handling Coverage Report
βββββββββββββββββββββββββββββββββββ
π Files analyzed: 42
π Functions analyzed: 156
- Async functions: 89
- Sync functions: 67
π Overall coverage: 68%
β Missing error handling (28 functions):
Critical (needs immediate attention):
1. api/payment.js:45 - processPayment()
Risk: High - Financial transaction
Recommendation: Add try/catch + transaction rollback
2. api/auth.js:23 - verifyToken()
Risk: High - Security critical
Recommendation: Add error handling + logging
3. db/users.js:78 - updateUserProfile()
Risk: Medium - Data mutation
Recommendation: Add validation + rollback
β οΈ Weak error handling (12 functions):
1. api/users.js:12 - getUserById()
Issue: Generic catch block without specific handling
Recommendation: Add error type differentiation
2. services/email.js:34 - sendWelcomeEmail()
Issue: Swallowed errors (empty catch block)
Recommendation: Add logging + alerting
π‘ Recommendations:
- Add error handling to 28 unprotected functions
- Improve 12 weak error handlers
- Target coverage: 90%+ for production readiness
π Usage Examples
Example 1: Protect API Route
User: "Add error handling to POST /api/orders"
Agent:
// β
Generated comprehensive error handling
app.post('/api/orders', async (req, res) => {
try {
// Validation
const { userId, items, paymentMethod } = req.body;
if (!userId || !items || !paymentMethod) {
return res.status(400).json({
error: 'Missing required fields',
required: ['userId', 'items', 'paymentMethod']
});
}
if (!Array.isArray(items) || items.length === 0) {
return res.status(400).json({
error: 'Items must be a non-empty array'
});
}
// Create order with error handling
let order;
try {
order = await createOrder({ userId, items, paymentMethod });
} catch (error) {
if (error.code === 'INSUFFICIENT_STOCK') {
return res.status(409).json({
error: 'Some items are out of stock',
unavailable: error.items
});
}
throw error; // Re-throw for outer handler
}
// Process payment with retry
let payment;
try {
payment = await retryWithBackoff(
() => processPayment(order.id, paymentMethod),
{ maxRetries: 3 }
);
} catch (error) {
// Rollback order
await cancelOrder(order.id);
if (error.code === 'PAYMENT_DECLINED') {
return res.status(402).json({
error: 'Payment declined',
reason: error.reason
});
}
throw error;
}
// Success
res.status(201).json({
orderId: order.id,
paymentId: payment.id,
status: 'confirmed'
});
} catch (error) {
logger.error('Order creation failed', {
body: req.body,
error: error.message,
stack: error.stack
});
res.status(500).json({
error: 'Failed to create order',
message: process.env.NODE_ENV === 'development'
? error.message
: 'Please try again later'
});
}
});
Example 2: Database Operations
User: "Add error handling to database queries"
Agent:
class UserRepository {
async findById(id) {
try {
const user = await db.query(
'SELECT * FROM users WHERE id = $1',
[id]
);
if (!user) {
throw new NotFoundError(`User ${id} not found`);
}
return user;
} catch (error) {
if (error instanceof NotFoundError) {
throw error;
}
logger.error('Database query failed', {
method: 'findById',
id,
error: error.message
});
throw new DatabaseError('Failed to fetch user', { cause: error });
}
}
async update(id, data) {
const client = await db.getClient();
try {
await client.query('BEGIN');
const result = await client.query(
'UPDATE users SET name = $1, email = $2 WHERE id = $3 RETURNING *',
[data.name, data.email, id]
);
if (result.rowCount === 0) {
throw new NotFoundError(`User ${id} not found`);
}
await client.query('COMMIT');
return result.rows[0];
} catch (error) {
await client.query('ROLLBACK');
if (error.code === '23505') { // Unique violation
throw new ConflictError('Email already exists');
}
if (error instanceof NotFoundError) {
throw error;
}
logger.error('User update failed', { id, data, error: error.message });
throw new DatabaseError('Failed to update user', { cause: error });
} finally {
client.release();
}
}
}
Example 3: External API Calls
User: "Add resilience to third-party API calls"
Agent:
class WeatherAPI {
constructor() {
this.breaker = new CircuitBreaker(this._fetch.bind(this), {
failureThreshold: 5,
resetTimeout: 60000
});
this.cache = new Map();
}
async getWeather(city) {
// Try cache first
const cached = this.cache.get(city);
if (cached && Date.now() - cached.timestamp < 300000) { // 5 min cache
logger.info('Returning cached weather', { city });
return cached.data;
}
try {
// Call with circuit breaker
const data = await this.breaker.execute(city);
// Update cache
this.cache.set(city, {
data,
timestamp: Date.now()
});
return data;
} catch (error) {
logger.error('Weather API failed', { city, error: error.message });
// Return stale cache if available
if (cached) {
logger.warn('Returning stale cached data', { city });
return { ...cached.data, _stale: true };
}
// Return default
return {
city,
temperature: null,
condition: 'Unknown',
_error: error.message
};
}
}
async _fetch(city) {
const response = await retryWithBackoff(
() => fetch(`https://api.weather.com/v1/${city}`),
{
maxRetries: 3,
shouldRetry: (error) => {
// Don't retry client errors
return !error.statusCode || error.statusCode >= 500;
}
}
);
if (!response.ok) {
throw new Error(`Weather API error: ${response.status}`);
}
return response.json();
}
}
βοΈ Configuration
Create .errorhandlerrc.json:
{
"coverage": {
"minimum": 80,
"target": 95,
"failOnBelow": true
},
"patterns": {
"enableRetry": true,
"enableCircuitBreaker": true,
"enableFallback": true,
"maxRetries": 3,
"retryDelay": 1000
},
"logging": {
"logLevel": "error",
"includeStack": true,
"structuredLogging": true
},
"customErrors": {
"baseClass": "AppError",
"errorTypes": [
"ValidationError",
"NotFoundError",
"UnauthorizedError",
"ForbiddenError"
]
}
}
π Error Types
Built-in Error Types
// Base error class
class AppError extends Error {
constructor(message, options = {}) {
super(message);
this.name = this.constructor.name;
this.statusCode = options.statusCode || 500;
this.code = options.code;
this.originalError = options.cause;
}
}
// Domain-specific errors
class ValidationError extends AppError {
constructor(message, fields) {
super(message, { statusCode: 400 });
this.fields = fields;
}
}
class NotFoundError extends AppError {
constructor(resource) {
super(`${resource} not found`, { statusCode: 404 });
this.resource = resource;
}
}
class UnauthorizedError extends AppError {
constructor(message = 'Unauthorized') {
super(message, { statusCode: 401 });
}
}
class ConflictError extends AppError {
constructor(message) {
super(message, { statusCode: 409 });
}
}
class ServiceUnavailableError extends AppError {
constructor(service) {
super(`${service} is temporarily unavailable`, { statusCode: 503 });
this.service = service;
}
}
π° Pricing
Free Tier
- β Error coverage analysis
- β Basic try/catch generation
- β Up to 10 files per project
Pro ($10/month)
- β Unlimited files
- β Advanced patterns (retry, circuit breaker)
- β Custom error types
- β CI/CD integration
- β Priority support
Enterprise ($79/month)
- β Everything in Pro
- β Team error handling policies
- β Error monitoring integration
- β Custom recovery strategies
- β SLA support
π Resources
- π Full Documentation
- π Error Handling Best Practices
- π¬ Discord Community
- π Report Issues
π License
MIT License - see LICENSE for details.
π Acknowledgments
Built with πΈ by ηΏ θ± (Cuihua) for the OpenClaw community.
Because production systems deserve bulletproof error handling.
Made with πΈ | Cuihua Series | ClawHub Pioneer
Transform fragile code into resilient systems.
Comments
Loading comments...
