Skip to main content
Runtime errors are thrown by the Workflow DevKit when internal operations fail. These errors indicate issues with API requests, workflow execution, or system state.

WorkflowError

The base class for all Workflow DevKit errors. Use with instanceof or the .is() method to catch any Workflow-related error.

Basic Usage

import { WorkflowError } from 'workflow';

try {
  await getRun(runId);
} catch (error) {
  if (error instanceof WorkflowError) {
    console.error('Workflow DevKit error:', error.message);
    console.error('Caused by:', error.cause);
  }
}

API Reference

class WorkflowError extends Error
Properties:
  • name - Always "WorkflowError"
  • message - Error message with optional documentation link
  • cause - The underlying error that caused this error (if any)
  • stack - Stack trace including cause chain
Methods:
  • WorkflowError.is(value) - Type guard to check if value is a WorkflowError
Constructor:
new WorkflowError(message: string, options?: {
  cause?: unknown;
  slug?: string;
})

Examples

import { WorkflowError } from 'workflow';
import { startWorkflow, getRun } from 'workflow/api';

try {
  const run = await startWorkflow('processOrder', { orderId: '123' });
  const result = await getRun(run.id);
} catch (error) {
  if (WorkflowError.is(error)) {
    console.error('Workflow operation failed:', error.message);
    
    if (error.cause) {
      console.error('Root cause:', error.cause);
    }
  } else {
    console.error('Non-workflow error:', error);
  }
}

WorkflowAPIError

Thrown when HTTP requests to the Workflow backend fail due to network issues, invalid requests, or server errors.

Basic Usage

import { WorkflowAPIError } from 'workflow';
import { startWorkflow } from 'workflow/api';

try {
  await startWorkflow('myWorkflow', input);
} catch (error) {
  if (error instanceof WorkflowAPIError) {
    console.error(`API error (${error.status}):`, error.message);
    console.error('URL:', error.url);
    console.error('Code:', error.code);
    
    if (error.retryAfter) {
      console.log(`Retry after ${error.retryAfter} seconds`);
    }
  }
}

API Reference

class WorkflowAPIError extends WorkflowError
Properties:
  • name - Always "WorkflowAPIError"
  • message - Error message
  • status - HTTP status code (e.g., 404, 500)
  • code - Error code from the API
  • url - The URL that was requested
  • retryAfter - Retry-After value in seconds (present on 429 responses)
  • cause - The underlying error (if any)
Methods:
  • WorkflowAPIError.is(value) - Type guard to check if value is a WorkflowAPIError

Examples

import { WorkflowAPIError } from 'workflow';
import { startWorkflow } from 'workflow/api';

async function startWorkflowWithRetry(
  name: string,
  input: unknown
) {
  try {
    return await startWorkflow(name, input);
  } catch (error) {
    if (WorkflowAPIError.is(error) && error.status === 429) {
      const retryAfterMs = (error.retryAfter || 60) * 1000;
      console.log(`Rate limited. Retrying after ${retryAfterMs}ms`);
      
      await new Promise(resolve => setTimeout(resolve, retryAfterMs));
      return await startWorkflow(name, input);
    }
    throw error;
  }
}
import { WorkflowAPIError } from 'workflow';
import { getRun } from 'workflow/api';

try {
  const run = await getRun('wrun_123');
} catch (error) {
  if (WorkflowAPIError.is(error)) {
    switch (error.status) {
      case 400:
        console.error('Bad request:', error.message);
        break;
      case 401:
        console.error('Unauthorized - check credentials');
        break;
      case 403:
        console.error('Forbidden - insufficient permissions');
        break;
      case 404:
        console.error('Workflow run not found');
        break;
      case 429:
        console.error('Rate limited, retry after:', error.retryAfter);
        break;
      case 500:
      case 502:
      case 503:
        console.error('Server error - try again later');
        break;
      default:
        console.error('API error:', error.status, error.message);
    }
  }
}

WorkflowRunFailedError

Thrown when a workflow run fails during execution. The cause property contains the underlying error with its message, stack trace, and optional error code.

Basic Usage

import { WorkflowRunFailedError } from 'workflow';
import { getRun } from 'workflow/api';

try {
  const run = await getRun(runId);
  const result = await run.result;
} catch (error) {
  if (error instanceof WorkflowRunFailedError) {
    console.error('Workflow run failed:', error.runId);
    console.error('Error:', error.cause.message);
    console.error('Stack:', error.cause.stack);
    
    if (error.cause.code) {
      console.error('Error code:', error.cause.code);
    }
  }
}

API Reference

class WorkflowRunFailedError extends WorkflowError
Properties:
  • name - Always "WorkflowRunFailedError"
  • message - Error message including run ID
  • runId - The ID of the failed workflow run
  • cause - The underlying error that caused the workflow to fail
    • message - Error message
    • stack - Stack trace
    • code - Optional error code
Methods:
  • WorkflowRunFailedError.is(value) - Type guard

Examples

import { WorkflowRunFailedError } from 'workflow';
import { getRun } from 'workflow/api';

try {
  const run = await getRun('wrun_abc123');
  const result = await run.result;
  console.log('Success:', result);
} catch (error) {
  if (WorkflowRunFailedError.is(error)) {
    console.error('Run ID:', error.runId);
    console.error('Failure message:', error.cause.message);
    
    // Log full stack trace for debugging
    console.error('Stack trace:', error.cause.stack);
    
    // Check for specific error codes
    if (error.cause.code === 'VALIDATION_ERROR') {
      console.error('Workflow failed due to validation error');
    }
  }
}

WorkflowRunNotCompletedError

Thrown when attempting to access the result of a workflow that hasn’t completed yet.

Basic Usage

import { WorkflowRunNotCompletedError } from 'workflow';
import { getRun } from 'workflow/api';

try {
  const run = await getRun(runId);
  const result = await run.result; // Throws if not completed
} catch (error) {
  if (error instanceof WorkflowRunNotCompletedError) {
    console.log('Run not completed yet. Status:', error.status);
    console.log('Run ID:', error.runId);
  }
}

API Reference

class WorkflowRunNotCompletedError extends WorkflowError
Properties:
  • name - Always "WorkflowRunNotCompletedError"
  • message - Error message
  • runId - The ID of the incomplete workflow run
  • status - Current status (e.g., "running", "waiting")
Methods:
  • WorkflowRunNotCompletedError.is(value) - Type guard

Examples

import { WorkflowRunNotCompletedError } from 'workflow';
import { getRun } from 'workflow/api';

async function waitForCompletion(runId: string, timeoutMs = 30000) {
  const startTime = Date.now();
  
  while (Date.now() - startTime < timeoutMs) {
    try {
      const run = await getRun(runId);
      const result = await run.result;
      return result;
    } catch (error) {
      if (WorkflowRunNotCompletedError.is(error)) {
        console.log(`Status: ${error.status}, waiting...`);
        await new Promise(resolve => setTimeout(resolve, 1000));
        continue;
      }
      throw error;
    }
  }
  
  throw new Error('Timeout waiting for workflow completion');
}

WorkflowRuntimeError

Thrown when the Workflow runtime encounters an internal error, such as serialization failures, invalid workflow functions, or other runtime problems.

Basic Usage

import { WorkflowRuntimeError } from 'workflow';

try {
  await startWorkflow('myWorkflow', input);
} catch (error) {
  if (error instanceof WorkflowRuntimeError) {
    console.error('Runtime error:', error.message);
    console.error('Cause:', error.cause);
  }
}

API Reference

class WorkflowRuntimeError extends WorkflowError
Properties:
  • name - Always "WorkflowRuntimeError"
  • message - Error message with optional documentation link
  • cause - The underlying error (if any)
Methods:
  • WorkflowRuntimeError.is(value) - Type guard

Common Runtime Errors

WorkflowRuntimeError is used for various runtime issues. The error message includes a link to documentation for common errors:
  • Serialization failed - Non-serializable data passed between workflow boundaries
  • Node.js module in workflow - Attempted to use Node.js modules in workflow functions
  • fetch in workflow - Attempted to use global fetch instead of workflow fetch
  • Timeout functions in workflow - Used setTimeout/setInterval instead of sleep
  • Invalid workflow function - Workflow function doesn’t have “use workflow” directive
  • Hook conflict - Multiple workflows trying to use the same hook token
  • Corrupted event log - Event log contains invalid or unconsumed events
See the Error Reference for detailed troubleshooting guides.

WorkflowRunNotFoundError

Thrown when attempting to access a workflow run that doesn’t exist.

Basic Usage

import { WorkflowRunNotFoundError } from 'workflow';
import { getRun } from 'workflow/api';

try {
  const run = await getRun('wrun_invalid');
} catch (error) {
  if (error instanceof WorkflowRunNotFoundError) {
    console.error('Run not found:', error.runId);
  }
}

API Reference

class WorkflowRunNotFoundError extends WorkflowError
Properties:
  • name - Always "WorkflowRunNotFoundError"
  • message - Error message
  • runId - The ID of the missing workflow run
Methods:
  • WorkflowRunNotFoundError.is(value) - Type guard

Examples

import { WorkflowRunNotFoundError } from 'workflow';
import { getRun } from 'workflow/api';

async function getRunSafely(runId: string) {
  try {
    return await getRun(runId);
  } catch (error) {
    if (WorkflowRunNotFoundError.is(error)) {
      console.warn(`Run ${error.runId} not found`);
      return null;
    }
    throw error;
  }
}

WorkflowRunCancelledError

Thrown when attempting to get results from a cancelled workflow run.

Basic Usage

import { WorkflowRunCancelledError } from 'workflow';
import { getRun } from 'workflow/api';

try {
  const run = await getRun(runId);
  const result = await run.result;
} catch (error) {
  if (error instanceof WorkflowRunCancelledError) {
    console.log('Workflow was cancelled:', error.runId);
  }
}

API Reference

class WorkflowRunCancelledError extends WorkflowError
Properties:
  • name - Always "WorkflowRunCancelledError"
  • message - Error message
  • runId - The ID of the cancelled workflow run
Methods:
  • WorkflowRunCancelledError.is(value) - Type guard

Examples

import { WorkflowRunCancelledError } from 'workflow';
import { getRun, cancelRun } from 'workflow/api';

async function processWithCancellation(runId: string) {
  try {
    const run = await getRun(runId);
    const result = await run.result;
    return result;
  } catch (error) {
    if (WorkflowRunCancelledError.is(error)) {
      console.log('Workflow was cancelled, cleaning up...');
      await performCleanup(error.runId);
      return null;
    }
    throw error;
  }
}

RunNotSupportedError

Thrown when attempting to operate on a workflow run that requires a newer World version than the current implementation supports. Users should upgrade their @workflow packages.

Basic Usage

import { RunNotSupportedError } from 'workflow';
import { getRun } from 'workflow/api';

try {
  const run = await getRun(runId);
} catch (error) {
  if (error instanceof RunNotSupportedError) {
    console.error('Run requires newer version');
    console.error('Run spec version:', error.runSpecVersion);
    console.error('Current version:', error.worldSpecVersion);
    console.error('Please upgrade: npm install workflow@latest');
  }
}

API Reference

class RunNotSupportedError extends WorkflowError
Properties:
  • name - Always "RunNotSupportedError"
  • message - Error message with upgrade instructions
  • runSpecVersion - The spec version required by the run
  • worldSpecVersion - The spec version supported by current World
Methods:
  • RunNotSupportedError.is(value) - Type guard

Examples

import { RunNotSupportedError } from 'workflow';
import { getRun } from 'workflow/api';

async function getRunWithVersionCheck(runId: string) {
  try {
    return await getRun(runId);
  } catch (error) {
    if (RunNotSupportedError.is(error)) {
      console.error('Version mismatch detected:');
      console.error(`  Required: ${error.runSpecVersion}`);
      console.error(`  Current:  ${error.worldSpecVersion}`);
      console.error('');
      console.error('To resolve this issue:');
      console.error('  npm install workflow@latest');
      console.error('  # or');
      console.error('  pnpm update workflow');
      
      throw new Error('Workflow package upgrade required');
    }
    throw error;
  }
}

Error Checking Patterns

Using instanceof

import { 
  WorkflowError,
  WorkflowAPIError,
  WorkflowRunFailedError 
} from 'workflow';

try {
  await startWorkflow('myWorkflow', input);
} catch (error) {
  if (error instanceof WorkflowRunFailedError) {
    // Handle workflow execution failure
  } else if (error instanceof WorkflowAPIError) {
    // Handle API error
  } else if (error instanceof WorkflowError) {
    // Handle any other workflow error
  }
}

Using Type Guards

import { 
  WorkflowAPIError,
  WorkflowRunNotFoundError,
  WorkflowRunCancelledError 
} from 'workflow';

try {
  const run = await getRun(runId);
  const result = await run.result;
} catch (error) {
  if (WorkflowRunNotFoundError.is(error)) {
    console.error('Run does not exist:', error.runId);
  } else if (WorkflowRunCancelledError.is(error)) {
    console.log('Run was cancelled:', error.runId);
  } else if (WorkflowAPIError.is(error)) {
    console.error('API error:', error.status, error.message);
  }
}

Comprehensive Error Handling

import {
  WorkflowError,
  WorkflowAPIError,
  WorkflowRunFailedError,
  WorkflowRunNotFoundError,
  WorkflowRunCancelledError,
  WorkflowRunNotCompletedError,
  RunNotSupportedError
} from 'workflow';
import { getRun } from 'workflow/api';

async function safeGetResult(runId: string) {
  try {
    const run = await getRun(runId);
    return await run.result;
  } catch (error) {
    // Check specific error types first
    if (WorkflowRunNotFoundError.is(error)) {
      throw new Error(`Workflow run ${error.runId} not found`);
    }
    
    if (WorkflowRunCancelledError.is(error)) {
      throw new Error(`Workflow run ${error.runId} was cancelled`);
    }
    
    if (WorkflowRunNotCompletedError.is(error)) {
      throw new Error(
        `Workflow run ${error.runId} has not completed (status: ${error.status})`
      );
    }
    
    if (WorkflowRunFailedError.is(error)) {
      throw new Error(
        `Workflow run ${error.runId} failed: ${error.cause.message}`
      );
    }
    
    if (RunNotSupportedError.is(error)) {
      throw new Error(
        `Workflow requires spec v${error.runSpecVersion}, ` +
        `but current version is v${error.worldSpecVersion}. ` +
        `Please upgrade: npm install workflow@latest`
      );
    }
    
    if (WorkflowAPIError.is(error)) {
      if (error.status === 429 && error.retryAfter) {
        throw new Error(
          `API rate limited. Retry after ${error.retryAfter} seconds`
        );
      }
      throw new Error(`API error (${error.status}): ${error.message}`);
    }
    
    // Catch-all for any other workflow errors
    if (WorkflowError.is(error)) {
      throw new Error(`Workflow error: ${error.message}`);
    }
    
    // Not a workflow error
    throw error;
  }
}

Best Practices

  1. Use type guards for cross-context safety
    • .is() methods work reliably across different module contexts
    • Safer than instanceof in some edge cases
  2. Check specific errors before generic ones
    • Check WorkflowRunFailedError before WorkflowError
    • Order matters when using inheritance-based checks
  3. Inspect error properties for details
    • Use status, code, runId for specific handling
    • Check retryAfter on API errors for rate limits
    • Access cause for underlying error details
  4. Log full error context
    • Include error.message, error.cause, and relevant properties
    • Helps debugging and monitoring
  5. Handle version errors proactively
    • Catch RunNotSupportedError and provide upgrade instructions
    • Monitor for version mismatches in production

Build docs developers (and LLMs) love