Skill flagged β€” suspicious patterns detected

ClawHub Security flagged this skill as suspicious. Review the scan results before using.

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...

⭐ 0· 86·0 current·0 all-time
Security Scan
VirusTotalVirusTotal
Benign
View report β†’
OpenClawOpenClaw
Benign
high confidence
βœ“
Purpose & Capability
Name/description (AI error handling assistant) align with what is included: node is the only required binary, the package contains a JS CLI (error-handler.js) and examples, and SKILL.md describes scanning/generating error handling. There are no unrelated cloud credentials or strange binaries requested.
βœ“
Instruction Scope
SKILL.md instructs the agent to scan code directories and generate try/catch/recovery code β€” this matches the provided error-handler.js implementation. The instructions do involve reading source files (expected for this purpose) but do not direct the agent to access unrelated system paths or to transmit data externally.
β„Ή
Install Mechanism
No install spec (instruction-only) and no external downloads; the only runtime requirement is node. Note: the skill includes executable JS files that will run locally if the agent invokes them; executing bundled code is normal but carries the usual risk of running third‑party scripts.
β„Ή
Credentials
The skill declares no required environment variables, which is reasonable. One included test file references process.env.JWT_SECRET (test-code.js), but the core CLI (error-handler.js) does not require secrets. This is a minor inconsistency to be aware of: example/test code references an env var that isn't declared or needed by the analyzer itself.
βœ“
Persistence & Privilege
always is false and the skill does not request persistent system-wide privileges or modify other skills' configs. Autonomous invocation is allowed (platform default) but not combined with any unusual permissions.
Assessment
This skill appears to do what it says: it scans JavaScript/TypeScript files and generates error handling. Before running it on a sensitive repository, review the bundled files (error-handler.js and test-code.js) to confirm there are no network calls, telemetry endpoints, or credential exfiltration logic. Be cautious when pointing the tool at directories that contain secrets (env files, config with API keys or private keys) because the analyzer will read files you tell it to scan; do not scan secrets unless you trust the code and execution environment. If you want extra safety, run the CLI in a sandboxed environment or inspect the generated output without applying changes automatically.
βœ—
test-code.js:15
Environment variable access combined with network send.
!
error-handler.js:40
File read combined with network send (possible exfiltration).
Patterns worth reviewing
These patterns may indicate risky behavior. Check the VirusTotal and OpenClaw results above for context-aware analysis before installing.

Like a lobster shell, security has layers β€” review code before you run it.

Runtime requirements

Binsnode
latestvk973e7b3nvmf0xyb21chyhxh8583hc69
86downloads
0stars
1versions
Updated 3w ago
v1.0.0
MIT-0

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


πŸ“œ 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...