How to Handle Errors Using Composio's Error Types and Validation

Composio provides a structured error-handling system built around the ComposioError base class, exposing consistent properties like code, possibleFixes, and cause to enable predictable error handling across all SDK operations.

The Composio SDK implements a robust hierarchy of error types to standardize failure handling across tools, triggers, and validation workflows. When you handle errors using Composio's error types and validation system, you gain access to machine-readable error codes, human-readable suggestions, and preserved stack traces that simplify debugging in production environments.

Understanding the Composio Error Hierarchy

The ComposioError Base Class

All SDK errors extend ComposioError, defined in ts/packages/core/src/errors/ComposioError.ts. This base class enforces a consistent interface across every error instance:

  • code: Machine-readable identifier (e.g., VALIDATION_ERROR, TOOL_EXECUTION_ERROR)
  • message: Human-readable description of what went wrong
  • possibleFixes: Array of actionable suggestions to resolve the issue
  • cause: The underlying error that triggered this failure (e.g., a Zod validation error)
  • stack: Standard JavaScript stack trace

Domain-Specific Error Types

The SDK organizes errors by domain under ts/packages/core/src/errors/:

  • ValidationErrors.ts: Wraps Zod schema failures (ValidationError, JsonSchemaToZodError)
  • ToolErrors.ts: Handles tool execution failures and provider-side errors
  • ToolkitErrors.ts: Manages toolkit discovery and permission issues
  • TriggerErrors.ts: Covers webhook and trigger configuration errors
  • SDKErrors.ts: Generic SDK failures including authentication and configuration errors

All exports are centralized in ts/packages/core/src/errors/index.ts for clean imports.

How Validation Errors Work

Composio uses Zod for runtime type validation. When you call a method with invalid arguments, the SDK catches the resulting ZodError and wraps it in a ValidationError instance.

The validation flow follows these steps:

  1. The SDK method receives input arguments typed with Zod schemas
  2. Zod validates the input against the schema definition
  3. If validation fails, the SDK catches the ZodError
  4. ValidationError extracts Zod issues and builds a user-friendly message with possibleFixes entries like "[invalid_type] userId – Expected string, received number"
  5. The populated ValidationError is thrown to the caller with the original Zod error preserved in cause

This approach preserves type safety while providing actionable debugging information.

Practical Examples to Handle Errors

Basic Try-Catch Implementation

Use instanceof checks to handle specific error types while maintaining a fallback for generic failures:

import { Composio } from '@composio/core';
import { ValidationError, ComposioError } from '@composio/core/errors';

const composio = new Composio({ apiKey: process.env.COMPOSIO_API_KEY });

async function run() {
  try {
    const result = await composio.tools.execute('GITHUB_CREATE_REPO', {
      userId: 'user_123',
      arguments: { repoName: 42 } // Intentional type error
    });
    console.log('Tool succeeded', result);
  } catch (err) {
    if (err instanceof ValidationError) {
      console.error('Validation failed:', err.message);
      console.error('Suggested fixes:', err.possibleFixes);
    } else if (err instanceof ComposioError) {
      console.error(`SDK Error (${err.code}): ${err.message}`);
    } else {
      console.error('Unexpected error:', err);
    }
  }
}

run();

Express Middleware Integration

Centralize error handling in Express applications by checking for ComposioError instances in your error middleware:

import express from 'express';
import { ComposioError, ValidationError } from '@composio/core/errors';

const app = express();
app.use(express.json());

app.post('/run-tool', async (req, res, next) => {
  try {
    const { toolSlug, arguments: args, userId } = req.body;
    const result = await composio.tools.execute(toolSlug, {
      userId,
      arguments: args,
    });
    res.json(result);
  } catch (err) {
    next(err);
  }
});

app.use((err: unknown, _req, res, _next) => {
  if (err instanceof ValidationError) {
    res.status(400).json({
      error: err.code,
      message: err.message,
      fixes: err.possibleFixes,
    });
    return;
  }

  if (err instanceof ComposioError) {
    res.status(500).json({ 
      error: err.code, 
      message: err.message 
    });
    return;
  }

  res.status(500).json({ 
    error: 'UNKNOWN', 
    message: String(err) 
  });
});

app.listen(3000);

Inspecting Zod Validation Details

Access the underlying Zod error for advanced debugging or automated remediation:

import { ValidationError } from '@composio/core/errors';
import type { ZodError } from 'zod';

try {
  await composio.tools.execute('SLACK_SEND_MESSAGE', {
    userId: 'user_abc',
    arguments: { channel: '', text: 123 }
  });
} catch (err) {
  if (err instanceof ValidationError && err.cause instanceof ZodError) {
    console.log('Raw Zod issues:', err.cause.issues);
    
    err.cause.issues.forEach(issue => {
      console.log(`Path: ${issue.path.join('.')} - ${issue.message}`);
    });
  }
}

Summary

  • ComposioError serves as the universal base class for all SDK errors, providing consistent code, message, possibleFixes, and cause properties.
  • Domain-specific subclasses like ValidationError, ToolErrors, and TriggerErrors live in ts/packages/core/src/errors/ and allow precise error handling.
  • Validation failures wrap Zod errors automatically, preserving detailed schema violation information while presenting user-friendly fix suggestions.
  • Use instanceof checks against ComposioError or its subclasses to implement type-safe error handling in both client scripts and server middleware.

Frequently Asked Questions

What is the difference between ComposioError and ValidationError?

ComposioError is the abstract base class that defines the common interface for all SDK errors, including properties like code and possibleFixes. ValidationError extends ComposioError specifically to wrap Zod schema validation failures, adding context about which input fields failed validation and why. When you catch a validation problem, it will be an instance of ValidationError, which is also an instance of ComposioError.

How do I access the original Zod error for debugging?

The original Zod error is preserved in the cause property of any ValidationError. You can access it by checking err.cause instanceof ZodError after importing the ZodError type from the zod package. This gives you access to the raw issues array containing detailed path information and specific constraint violations.

Can I use Composio error types in Express middleware?

Yes, Composio error types work seamlessly with Express error-handling middleware. Import ComposioError and its subclasses from @composio/core/errors, then use instanceof checks in your error middleware to return appropriate HTTP status codes and JSON responses. The possibleFixes array is particularly useful for returning actionable error details to API clients.

Where are the error classes defined in the Composio repository?

All error classes are located in ts/packages/core/src/errors/. The base class ComposioError is defined in ComposioError.ts, while domain-specific errors reside in separate files like ValidationErrors.ts, ToolErrors.ts, ToolkitErrors.ts, TriggerErrors.ts, and SDKErrors.ts. A barrel export in index.ts simplifies importing these classes into your application.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →