or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

arguments.mdcommands.mderrors.mdhelp.mdindex.mdoptions.md
tile.json

errors.mddocs/

Error Handling

Specialized error classes for handling command-line parsing errors, invalid arguments, custom error scenarios with exit code management, and comprehensive error handling patterns.

Capabilities

CommanderError Class

Base error class for all Commander-related errors with exit code and error code support.

/**
 * Base error class for Commander errors
 * Extends the standard Error class with exit codes and error identification
 */
class CommanderError extends Error {
  /**
   * Create a new CommanderError
   * @param exitCode - Suggested exit code for process.exit
   * @param code - Error code identifier for programmatic handling
   * @param message - Human-readable error message
   */
  constructor(exitCode: number, code: string, message: string);
  
  // Properties
  exitCode: number;         // Suggested exit code
  code: string;            // Error code identifier
  message: string;         // Error message
  nestedError?: string;    // Optional nested error information
}

Usage Examples:

import { CommanderError } from 'commander';

// Custom error handling
try {
  program.parse(process.argv);
} catch (error) {
  if (error instanceof CommanderError) {
    console.error(`Error ${error.code}: ${error.message}`);
    process.exit(error.exitCode);
  }
  throw error;
}

// Creating custom CommanderError
throw new CommanderError(2, 'custom.validation', 'Custom validation failed');

InvalidArgumentError Class

Specialized error for invalid command arguments or option values.

/**
 * Error for invalid command arguments or option values
 * Extends CommanderError with predefined exit code and error code
 */
class InvalidArgumentError extends CommanderError {
  /**
   * Create a new InvalidArgumentError
   * @param message - Explanation of why the argument is invalid
   */
  constructor(message: string);
}

Usage Examples:

import { InvalidArgumentError } from 'commander';

// In custom argument parser
const parsePort = (value) => {
  const port = parseInt(value);
  if (isNaN(port) || port < 1 || port > 65535) {
    throw new InvalidArgumentError(`Port must be a number between 1 and 65535, got: ${value}`);
  }
  return port;
};

// In option argument parser
const parsePercentage = (value) => {
  const num = parseFloat(value);
  if (isNaN(num) || num < 0 || num > 100) {
    throw new InvalidArgumentError(`Percentage must be between 0 and 100, got: ${value}`);
  }
  return num;
};

program
  .option('-p, --port <number>', 'server port', parsePort)
  .option('--opacity <percent>', 'opacity percentage', parsePercentage);

InvalidOptionArgumentError (Deprecated)

Deprecated alias for InvalidArgumentError, maintained for backward compatibility.

/**
 * Deprecated alias for InvalidArgumentError
 * @deprecated Use InvalidArgumentError instead
 */
const InvalidOptionArgumentError = InvalidArgumentError;

Command Error Handling

Built-in error handling methods on the Command class.

interface Command {
  /**
   * Display error message and exit
   * @param message - Error message to display
   * @param errorOptions - Error configuration options
   */
  error(message: string, errorOptions?: ErrorOptions): never;
  
  /**
   * Override exit behavior for error handling
   * @param callback - Custom exit handler
   * @returns this command for chaining
   */
  exitOverride(callback?: (err: CommanderError) => never | void): this;
}

interface ErrorOptions {
  /** Error code identifier */
  code?: string;
  /** Suggested exit code */
  exitCode?: number;
}

Built-in Error Codes

Commander uses specific error codes for different parsing and validation scenarios:

// Built-in error codes used by Commander
const COMMANDER_ERROR_CODES = {
  // Command parsing errors
  'commander.unknownCommand': 'Unknown command specified',
  'commander.unknownOption': 'Unknown option specified',
  'commander.missingMandatoryOptionValue': 'Required option value not provided',
  'commander.optionMissingArgument': 'Option requires an argument',
  'commander.invalidArgument': 'Invalid argument value provided',
  'commander.missingArgument': 'Required argument not provided',
  'commander.excessArguments': 'Too many arguments provided',
  
  // Option conflicts and requirements
  'commander.conflictingOption': 'Conflicting options specified',
  'commander.missingMandatoryOption': 'Required option not specified',
  
  // Help and version
  'commander.help': 'Help requested',
  'commander.version': 'Version requested'
};

Usage Examples:

// Display error and exit
if (!process.env.API_KEY) {
  program.error('API_KEY environment variable is required', {
    code: 'missing.apikey',
    exitCode: 1
  });
}

// Custom exit handling
program.exitOverride((err) => {
  if (err.code === 'commander.invalidArgument') {
    console.error(`Invalid input: ${err.message}`);
    console.error('Run with --help for usage information');
  }
  process.exit(err.exitCode);
});

Common Error Patterns

Validation Errors

// File existence validation
const validateFileExists = (filepath) => {
  if (!fs.existsSync(filepath)) {
    throw new InvalidArgumentError(`File not found: ${filepath}`);
  }
  return filepath;
};

// Format validation
const validateEmail = (email) => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(email)) {
    throw new InvalidArgumentError(`Invalid email format: ${email}`);
  }
  return email;
};

// Range validation
const validateRange = (min, max) => (value) => {
  const num = Number(value);
  if (isNaN(num) || num < min || num > max) {
    throw new InvalidArgumentError(`Value must be between ${min} and ${max}, got: ${value}`);
  }
  return num;
};

program
  .option('-f, --file <path>', 'input file', validateFileExists)
  .option('-e, --email <address>', 'email address', validateEmail)
  .option('-p, --port <number>', 'port number', validateRange(1, 65535));

Choice Validation

// Using built-in choices validation
program
  .option('-l, --log-level <level>', 'logging level')
  .choices(['error', 'warn', 'info', 'debug']);

// Custom choice validation with suggestions
const validateLogLevel = (value) => {
  const validLevels = ['error', 'warn', 'info', 'debug', 'trace'];
  if (!validLevels.includes(value)) {
    const suggestions = validLevels.filter(level => 
      level.startsWith(value) || value.startsWith(level)
    );
    const suggestion = suggestions.length > 0 
      ? ` Did you mean: ${suggestions.join(', ')}?` 
      : '';
    throw new InvalidArgumentError(`Invalid log level: ${value}.${suggestion}`);
  }
  return value;
};

Async Validation

// Async validation in action handlers
program
  .command('deploy <environment>')
  .action(async (environment) => {
    try {
      const config = await loadEnvironmentConfig(environment);
      await deploy(config);
    } catch (error) {
      if (error.code === 'ENOENT') {
        program.error(`Environment configuration not found: ${environment}`, {
          code: 'deploy.config.missing',
          exitCode: 1
        });
      }
      throw error;
    }
  });

Error Recovery and Suggestions

// Command suggestion on unknown commands
program.exitOverride((err) => {
  if (err.code === 'commander.unknownCommand') {
    const availableCommands = program.commands.map(cmd => cmd.name());
    const suggestion = availableCommands.find(cmd => 
      cmd.startsWith(err.message.split("'")[1]?.slice(0, 3) || '')
    );
    
    console.error(err.message);
    if (suggestion) {
      console.error(`Did you mean: ${suggestion}?`);
    }
    console.error('Run --help to see available commands');
  }
  process.exit(err.exitCode);
});

// Option suggestion configuration
program.showSuggestionAfterError(true); // Default behavior

Error Context and Debugging

// Enhanced error context
const createEnhancedError = (message, context = {}) => {
  const error = new InvalidArgumentError(message);
  error.context = context;
  return error;
};

// Validation with context
const validateConfigFile = (filepath) => {
  try {
    const config = JSON.parse(fs.readFileSync(filepath, 'utf8'));
    return config;
  } catch (parseError) {
    throw createEnhancedError(
      `Invalid JSON in config file: ${filepath}`,
      { 
        parseError: parseError.message,
        line: parseError.lineNumber,
        column: parseError.columnNumber
      }
    );
  }
};

// Debug-friendly error handling
program.exitOverride((err) => {
  if (process.env.DEBUG) {
    console.error('Error details:', {
      code: err.code,
      exitCode: err.exitCode,
      stack: err.stack,
      context: err.context
    });
  } else {
    console.error(err.message);
  }
  process.exit(err.exitCode);
});

Error Handling Best Practices

Early Validation

// Validate dependencies before command execution
program
  .hook('preAction', (thisCommand) => {
    // Check required environment variables
    const requiredEnvVars = ['API_KEY', 'DATABASE_URL'];
    for (const envVar of requiredEnvVars) {
      if (!process.env[envVar]) {
        thisCommand.error(`Missing required environment variable: ${envVar}`, {
          code: 'env.missing',
          exitCode: 1
        });
      }
    }
  });

Graceful Error Messages

// User-friendly error messages
const parseSize = (value) => {
  const match = value.match(/^(\d+(?:\.\d+)?)(b|kb|mb|gb)$/i);
  if (!match) {
    throw new InvalidArgumentError(
      `Invalid size format: ${value}. Use format like: 100b, 1.5kb, 2mb, 1gb`
    );
  }
  
  const [, amount, unit] = match;
  const multipliers = { b: 1, kb: 1024, mb: 1024**2, gb: 1024**3 };
  return parseFloat(amount) * multipliers[unit.toLowerCase()];
};

Error Code Conventions

// Consistent error code naming
const ERROR_CODES = {
  VALIDATION: {
    INVALID_FORMAT: 'validation.format',
    OUT_OF_RANGE: 'validation.range',
    MISSING_REQUIRED: 'validation.required'
  },
  FILE: {
    NOT_FOUND: 'file.notfound',
    ACCESS_DENIED: 'file.access',
    INVALID_FORMAT: 'file.format'
  },
  NETWORK: {
    CONNECTION_FAILED: 'network.connection',
    TIMEOUT: 'network.timeout',
    UNAUTHORIZED: 'network.auth'
  }
};

// Usage in validators
const validateUrl = (url) => {
  try {
    new URL(url);
    return url;
  } catch {
    throw new CommanderError(1, ERROR_CODES.VALIDATION.INVALID_FORMAT, `Invalid URL: ${url}`);
  }
};

Types

interface ErrorOptions {
  /** Error code identifier for programmatic handling */
  code?: string;
  /** Suggested exit code for process termination */
  exitCode?: number;
}