Exception Management

BoxLang provides powerful exception handling with try/catch/finally constructs, multi-catch support, Java exception interop, and a rich exception type hierarchy.

Exception management in BoxLang allows you to gracefully handle errors, recover from failures, and maintain application stability. BoxLang supports traditional structured exception handling, multi-type catching, nested catches, and seamless interoperability with Java exceptions.

🎯 Try/Catch/Finally Basics

The BoxLang exception handling system consists of three core constructs:

Construct
Purpose
Required

try

Wraps code that might throw exceptions

✅ Yes

catch

Handles specific exception types when they occur

⚠️ At least one

finally

Executes cleanup code regardless of success/failure

❌ Optional

Basic Try/Catch Structure

try {
    // Code that might throw an exception
    result = riskyOperation()
} catch ( any e ) {
    // Handle any type of exception
    logError( e )
    result = defaultValue
} finally {
    // Always executes - perfect for cleanup
    closeConnections()
}

Exception Flow Diagram

Execution Guarantee

The finally block is guaranteed to execute regardless of:

  • ✅ Whether an exception occurs

  • ✅ Whether a catch block handles the exception

  • ✅ Whether a return statement is encountered

  • ✅ Whether another exception is thrown in the catch block

🎭 Catch Block Syntax

BoxLang offers flexible syntax for catch blocks, allowing both quoted and unquoted type names:

Syntax Variations

Flexible Naming: The exception variable name (e in the examples above) can be any valid identifier. Common conventions include e, ex, exception, or descriptive names like dbError, ioEx, etc.

Catch Block Order

Catch blocks are evaluated top to bottom, and the first matching type is executed. Order from most specific to most general:

🔀 Multi-Catch Statements

BoxLang supports multi-catch syntax using the pipe (|) operator, allowing a single catch block to handle multiple exception types:

Multi-Catch Syntax

Grammar Definition

From the BoxLang grammar (BoxGrammar.g4):

This allows:

  • Zero or more exception types before the variable name: ct += expression?

  • Multiple types separated by pipes: (PIPE ct += expression)*

  • The exception variable name at the end: ex = expression

Multi-Catch Examples

Multi-Catch Benefits

Reduces Code Duplication - Handle similar exceptions with the same logic

Improves Readability - Groups related exception handling together

Maintains Specificity - Still allows granular error handling when needed

📦 Exception Types

BoxLang has a rich exception type hierarchy supporting native exceptions, custom exceptions, and Java exceptions.

Exception Type Categories

Category
Description
Example Types

Native

Built into BoxLang runtime

DatabaseException, KeyNotFoundException

Custom

User-defined exception types

InvalidOrderException, PaymentFailedException

Java

Java exceptions from interop

java.io.IOException, java.sql.SQLException

Native BoxLang Exceptions

BoxLang provides comprehensive built-in exception types:

Application & Runtime Exceptions
  • BoxRuntimeException - Base exception for BoxLang runtime errors

  • ExpressionException - Expression or evaluation errors

  • CustomException - Base for user-defined exceptions

  • AbortException - Application abort/stop requests

  • UnmodifiableException - Modification of immutable objects

  • BoxValidationException - Validation failures

Data & Type Exceptions
  • KeyNotFoundException - Missing struct key

  • NoElementException - Variable does not exist

  • BoxCastException - Type casting failure

  • ScopeNotFoundException - Scope not available in runtime

Database Exceptions
  • DatabaseException - Base for all database errors

    • Connection failures

    • Query execution errors

    • Transaction errors

I/O Exceptions
  • BoxIOException - I/O operation failures

  • MissingIncludeException - Template file not found

Java Interop Exceptions
  • ClassNotFoundBoxLangException - Java class not found

  • NoMethodException - Method doesn't exist or match arguments

  • NoFieldException - Field doesn't exist on Java class

  • NoConstructorException - Constructor doesn't match arguments

  • AbstractClassException - Cannot instantiate abstract class

Parsing & Configuration Exceptions
  • ParseException - Source file parsing errors

  • ConfigurationException - Runtime/module configuration errors

Concurrency Exceptions
  • LockException - Lock acquisition or timeout failures

Custom Exception Types

Define your own exception types for application-specific errors:

Custom Exception Naming Conventions

Convention
Example
Use Case

Descriptive

InvalidEmailException

Clear, self-documenting

Domain-specific

PaymentDeclinedException

Business logic errors

Technical

CircularDependencyException

System/framework errors

Module-prefixed

MyModule.ValidationException

Avoid name conflicts

🚀 Throwing Exceptions

Use the throw() function to raise exceptions in your code. BoxLang provides flexible exception throwing with multiple syntax options.

Throw Syntax Options

Throw Parameters

Parameter
Type
Required
Description

message

any

⚠️ *

Main error message (can also be exception object)

type

string

Exception type (default: "Custom")

detail

string

Detailed description of the error

errorCode

string

Custom error code for tracking

extendedInfo

any

Additional data (struct, array, string, etc.)

object

Throwable

Java exception object to throw or wrap

Flexible Message: The message parameter can accept a string OR a Java exception object. If an exception object is provided, it's automatically moved to the object parameter.

Basic Throw Examples

Throw with Extended Info

The extendedInfo parameter can hold any data type, making it perfect for passing context:

Throwing Objects

You can throw Java exception objects directly or wrap them in BoxLang exceptions:

Exception Object Structure

When caught, exceptions provide a rich structure:

🔁 Rethrowing Exceptions

The rethrow statement re-raises the current exception, preserving all original information including the stack trace, type, and message.

Rethrow Syntax

When to Use Rethrow

Use rethrow when you want to:

  • ✅ Log an exception but let it propagate up

  • ✅ Perform cleanup before re-raising the error

  • ✅ Add context in a catch block then pass it on

  • ✅ Conditionally handle some exceptions and rethrow others

Rethrow vs Throw

Statement
Behavior
Stack Trace
Use Case

rethrow

Re-raises current exception

✅ Preserved

Logging, cleanup, partial handling

throw( e )

Throws new exception

❌ New stack trace

Wrapping, transformation

Rethrow Examples

Example 1: Logging Before Propagating

Example 2: Cleanup with Rethrow

Example 3: Conditional Rethrow

Example 4: Rethrow After Adding Context

Rethrow in Finally

You can use rethrow in a finally block to re-raise exceptions after cleanup:

☕ Java Exception Interop

BoxLang provides seamless interoperability with Java exceptions, allowing you to catch and throw Java exceptions just like native BoxLang exceptions.

Catching Java Exceptions

You can catch Java exceptions using their fully qualified class name or simple class name:

Simplified Java Exception Names

BoxLang also supports catching Java exceptions by their simple class name:

Catching Any Java Exception

Use any to catch all exceptions, including Java exceptions:

Throwing Java Exceptions

You can throw Java exceptions directly:

Java Exception Hierarchy

BoxLang respects Java's exception hierarchy when catching:

Java Exception Examples

Example 1: File Operations

Example 2: JDBC Database Operations

Example 3: Multi-Catch with Java Exceptions

Accessing Java Exception Properties

Java exceptions caught in BoxLang provide access to Java methods:

🪆 Nested Exception Handling

BoxLang supports nested try/catch blocks, allowing you to handle exceptions at multiple levels with different strategies.

Why Nest Try/Catch?

  • Granular Error Handling - Handle specific operations differently

  • Cleanup Isolation - Separate cleanup logic for different resources

  • Error Recovery - Attempt recovery at different levels

  • Context-Specific Handling - Different error strategies in different contexts

Nested Try/Catch Example

Nested Catch with Different Strategies

Nested Try in Catch Block

You can use try/catch inside catch blocks for error recovery:

Nested Try in Finally Block

You can use try/catch in finally blocks for safe cleanup:

Complex Nested Example

💡 Best Practices

1. Catch Specific Exceptions First

Always order catch blocks from most specific to most general:

2. Always Include Finally for Cleanup

Use finally blocks to guarantee resource cleanup:

3. Provide Meaningful Error Messages

Include context in your exception messages:

4. Use Extended Info for Debugging

Pass structured data in extendedInfo for better debugging:

5. Don't Swallow Exceptions

Avoid empty catch blocks that hide errors:

6. Use Multi-Catch for Similar Handling

Group related exceptions with multi-catch:

7. Rethrow After Adding Context

Add context before rethrowing to help debugging:

8. Validate Early, Fail Fast

Validate inputs before processing to throw clear exceptions:

9. Use Custom Exception Types

Create domain-specific exception types for clarity:

10. Document Exception Types

Document what exceptions your functions throw:

📊 Exception Handling Patterns

Pattern 1: Try-Catch-Log-Rethrow

Pattern 2: Try-Catch-Recover

Pattern 3: Try-Catch-Cleanup-Rethrow

Pattern 4: Try-Catch-Wrap

Pattern 5: Try-Catch-Accumulate


📋 Summary

BoxLang exception management provides:

Try/Catch/Finally - Structured exception handling

Multi-Catch - Handle multiple exception types in one block

Flexible Syntax - Quoted/unquoted types, any variable names

Rich Exception Types - Native, custom, and Java exceptions

Throw/Rethrow - Create and propagate exceptions

Java Interop - Seamless Java exception handling

Nested Handling - Multi-level error strategies

Extended Info - Pass structured data with exceptions

Last updated

Was this helpful?