Error Handling and Exception Patterns in the nGPT CLI: A Complete Guide

The nGPT CLI implements a centralized, three-layer error handling architecture that validates arguments before execution, funnels all runtime exceptions through a single handler in ngpt/cli/handlers/error_handler.py, and returns POSIX-compliant exit codes (2 for validation errors, 130 for interrupts, and 1 for unexpected failures).

The nGPT command-line interface, developed in the nazdridoy/ngpt repository, employs sophisticated error handling and exception patterns to ensure robust user feedback and graceful failure recovery. By centralizing exception management and enforcing strict validation at the entry point, the CLI maintains clean separation between user input errors, runtime failures, and system interrupts.

Centralized Error Handling Architecture

The nGPT CLI follows a centralized, layered approach that keeps the core execution flow readable while providing clear, coloured feedback to the user. This architecture divides responsibilities across three distinct layers: argument validation, runtime exception funneling, and graceful termination handling.

The Three-Layer Validation Strategy

The error handling stack operates through three coordinated layers:

  • Argument Validation Layer: Detects misuse of CLI flags, missing required arguments, and incompatible option combinations before any heavy processing begins.
  • Exception Funnel Layer: Catches any exception that bubbles out of the command dispatch and routes it through a single handler that decides whether to show a traceback or a concise error message.
  • Termination Layer: Handles user-initiated aborts (Ctrl-C) with friendly messaging and appropriate exit codes.

Exception Funnel in the Entry Point

The entry point in ngpt/cli/main.py implements the primary exception handling flow using nested try-except blocks:


# ngpt/cli/main.py

try:
    args = validate_args(args)                     # ← validation layer

except ValueError as e:
    handle_validation_error(e)                     # ← validation-error shortcut

try:
    dispatch_mode(client, args, logger=logger)    # → business logic

except KeyboardInterrupt:
    handle_keyboard_interrupt()                    # ← graceful abort

except Exception as e:
    handle_exception(e)                           # ← CLI-wide funnel

This structure ensures that validation errors receive immediate attention before API calls or file operations begin, while unexpected runtime failures converge through a single exit path.

Validation Layer and Argument Checking

The nGPT CLI enforces strict input validation through the validate_args function in ngpt/cli/args.py, which raises ValueError for any detected misuse, allowing the entry point to catch and route these errors appropriately.

Pre-execution Validation in validate_args

The validate_args function performs comprehensive checks before execution:

  • Range validation: Ensures temperature values fall between 0.0 and 2.0
  • Mutual exclusivity: Prevents incompatible flag combinations (e.g., --pipe used with --text)
  • Dependency checking: Verifies optional dependencies like BeautifulSoup are available when flags like --web-search are used
  • Input validation: Confirms that piped input is actually available when --pipe is specified

When any check fails, the function raises ValueError with a descriptive message:


# ngpt/cli/args.py

def validate_args(args):
    if args.temperature is not None and not (0.0 <= args.temperature <= 2.0):
        raise ValueError("Temperature must be between 0.0 and 2.0")
    
    if args.pipe and args.text:
        raise ValueError("Cannot use --pipe with --text")
    
    if args.pipe and sys.stdin.isatty():
        raise ValueError("--pipe was specified but no input is piped")
    
    # Additional validation logic...

    return args

Custom Argparse Error Rendering

The CLI overrides the default argparse.ArgumentParser.error method within setup_argument_parser in ngpt/cli/args.py to provide coloured error prefixes and usage information instead of plain-text messages:


# ngpt/cli/args.py

def setup_argument_parser():
    parser = argparse.ArgumentParser(...)
    
    def custom_error(message):
        print(f"{Colors.ERROR}error:{Colors.RESET} {message}", file=sys.stderr)
        parser.print_usage(sys.stderr)
        sys.exit(2)
    
    parser.error = custom_error
    return parser

This ensures that parsing errors (missing required arguments, unknown flags) receive the same visual treatment as validation errors, maintaining consistency across all error states.

Runtime Exception Management

Once argument validation passes, the nGPT CLI employs a centralized exception funnel to handle unexpected runtime errors, ensuring consistent user feedback and appropriate exit codes.

The handle_exception Funnel

The handle_exception function in ngpt/cli/handlers/error_handler.py serves as the single catch-all for unexpected exceptions:


# ngpt/cli/handlers/error_handler.py

def handle_exception(e, debug=False):
    if debug:
        import traceback
        traceback.print_exc()
    else:
        print(f"{Colors.ERROR}Error:{Colors.RESET} {e}", file=sys.stderr)
    
    sys.exit(1)

This implementation provides two critical features:

  • User-friendly output: By default, it prints a concise, coloured error message without exposing internal stack traces
  • Debug capability: When debug=True, it prints the full traceback for development or troubleshooting scenarios

Graceful Keyboard Interrupt Handling

The CLI provides specialized handling for KeyboardInterrupt exceptions through handle_keyboard_interrupt in the same module:


# ngpt/cli/handlers/error_handler.py

def handle_keyboard_interrupt():
    print(f"\n{Colors.WARNING}Operation cancelled by user.{Colors.RESET} Exiting gracefully.")
    sys.exit(130)

This handler:

  • Prints a friendly cancellation message using warning colours from ngpt/ui/colors.py
  • Exits with status code 130, which follows the POSIX convention for processes terminated by SIGINT (128 + 2)

Exit Codes and POSIX Compliance

The nGPT CLI adheres to standard Unix exit code conventions, allowing shell scripts and automation tools to reliably detect failure modes:

Exit Code Meaning Trigger
0 Success Normal completion
2 Argument/Validation Error Invalid flags, missing dependencies, or argparse errors
130 Interrupted User pressed Ctrl-C (SIGINT)
1 General Error Unexpected runtime exceptions

This standardization ensures that CI/CD pipelines can distinguish between usage errors (exit 2) and runtime failures (exit 1), while interactive users receive immediate feedback about cancellation (exit 130).

Error Handling Examples in Practice

Triggering a Validation Error

Attempting to set an invalid temperature range demonstrates the validation layer:


# Temperature must be between 0.0 and 2.0

ngpt --temperature 5.0 "Hello world"

Result:


error: Temperature must be between 0.0 and 2.0

This error is raised by validate_args in ngpt/cli/args.py and handled by handle_validation_error in ngpt/cli/handlers/error_handler.py, exiting with status code 2.

Using --pipe Without Piped Input

The CLI detects when flags requiring stdin are used inappropriately:


# Attempting to use --pipe in an interactive terminal

ngpt --pipe "Summarise {}"

Result:


error: --pipe was specified but no input is piped. Use echo 'content' | ngpt --pipe 'prompt with {}'

This check occurs within validate_args before any API client initialization, preventing unnecessary network overhead for invalid usage patterns.

Graceful Cancellation During Interactive Sessions

When a user aborts an ongoing operation:


# Start an interactive session and press Ctrl-C

ngpt -i

Result:


Operation cancelled by user. Exiting gracefully.

The handle_keyboard_interrupt function ensures the terminal returns to a clean state with exit code 130, following POSIX conventions for interrupted processes.

Debug Mode for Development

When troubleshooting unexpected failures, the centralized handler supports full traceback output:


# Example internal usage during development

from ngpt.cli.handlers.error_handler import handle_exception

try:
    risky_operation()
except Exception as e:
    handle_exception(e, debug=True)  # Prints full traceback

This pattern allows developers to access detailed stack traces while ensuring end-users only see sanitized error messages during normal operation.

Summary

The nGPT CLI implements a robust, layered error handling strategy that prioritizes user experience and POSIX compliance:

  • Centralized exception funneling through handle_exception in ngpt/cli/handlers/error_handler.py ensures consistent error presentation and exit codes
  • Pre-execution validation via validate_args in ngpt/cli/args.py catches configuration errors before resource-intensive operations begin
  • Standardized exit codes distinguish between validation failures (2), user interrupts (130), and runtime errors (1)
  • Graceful degradation for keyboard interrupts preserves terminal state and provides clear cancellation feedback
  • Debug mode support allows full tracebacks during development while protecting end-users from internal stack traces

Frequently Asked Questions

How does nGPT handle invalid command-line arguments?

nGPT validates arguments through the validate_args function in ngpt/cli/args.py, which raises ValueError for any invalid configuration such as temperature values outside the 0.0-2.0 range or incompatible flag combinations. These validation errors are caught in ngpt/cli/main.py and routed to handle_validation_error in ngpt/cli/handlers/error_handler.py, which prints a coloured error message and exits with status code 2.

What exit codes does nGPT use for different error types?

The CLI follows POSIX conventions: exit code 2 indicates argument validation errors or argparse failures, exit code 130 signals that the user interrupted the process with Ctrl-C (SIGINT), and exit code 1 represents general runtime exceptions or unexpected failures. Successful operations return exit code 0. This standardization allows shell scripts and automation tools to distinguish between usage errors and system failures.

Where is the centralized exception handling implemented?

The centralized exception funnel is implemented in ngpt/cli/handlers/error_handler.py through the handle_exception function, which serves as the catch-all for unexpected runtime errors. The entry point in ngpt/cli/main.py wraps the main dispatch logic in a try-except block that routes all non-validation exceptions to this handler, ensuring consistent error formatting and exit behaviour across the entire application.

How does nGPT handle keyboard interrupts gracefully?

When a user presses Ctrl-C during operation, the KeyboardInterrupt exception is caught in the main execution block of ngpt/cli/main.py and passed to handle_keyboard_interrupt in ngpt/cli/handlers/error_handler.py. This function prints a friendly cancellation message using warning colours from ngpt/ui/colors.py and exits with status code 130, following the POSIX convention for SIGINT termination while preserving terminal state.

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 →