BamlAbortError

Overview

BamlAbortError is thrown when a BAML function call is cancelled via an abort controller. This error indicates that the operation was intentionally stopped rather than failing due to an actual error condition.

Class Definition

export class BamlAbortError extends Error {
public readonly name: string = 'BamlAbortError'
public readonly reason?: any
public readonly detailed_message: string
constructor(message: string, reason?: any, detailed_message: string = '') {
super(message)
this.reason = reason
this.detailed_message = detailed_message
}
}

Properties

message

Type: string

Description of why the operation was aborted. This is typically a generic message like “Operation aborted” unless a specific message was provided during cancellation.

reason

Type: any (TypeScript/Python) / interface{} (Go) / Object (Ruby)

Optional additional context about the cancellation. This can be any value provided when calling the abort() method.

name

Type: string

Always returns "BamlAbortError" for easy error type identification.

detailed_message

Type: string

Comprehensive error information that includes the complete history of all failed attempts when using fallback clients or retry policies. For abort errors, this typically contains the same information as message but may include additional debugging details about the cancellation context.

Error Detection

TypeScript

import { BamlAbortError } from '../../../baml_client'
try {
const result = await b.FunctionName(input, {
abortController: controller
})
} catch (error) {
// Method 1: instanceof check (recommended)
if (error instanceof BamlAbortError) {
console.log('Operation was cancelled')
}
// Method 2: name check (works with minification)
if (error.name === 'BamlAbortError') {
console.log('Operation was cancelled')
}
}

Python

from baml_py import BamlAbortError
try:
result = await b.FunctionName(
input,
baml_options={"abort_controller": controller}
)
except BamlAbortError as e:
print(f"Operation was cancelled: {e}")
if e.reason:
print(f"Reason: {e.reason}")
except Exception as e:
# Handle other errors
raise

Go

import (
"context"
"errors"
)
result, err := b.FunctionName(ctx, input)
if err != nil {
if errors.Is(err, context.Canceled) {
// Direct cancellation
fmt.Println("Operation was cancelled")
} else if errors.Is(err, context.DeadlineExceeded) {
// Timeout-based cancellation
fmt.Println("Operation timed out")
} else {
// Other error
return err
}
}

Ruby

begin
result = b.function_name(
input,
baml_options: { abort_controller: controller }
)
rescue Baml::AbortError => e
puts "Operation was cancelled: #{e.message}"
puts "Reason: #{e.reason}" if e.reason
rescue => e
# Handle other errors
raise
end

Common Patterns

Distinguishing Cancellation Types

try {
const result = await b.FunctionName(input, {
abortController: controller
})
} catch (error) {
if (error instanceof BamlAbortError) {
if (error.reason === 'user_cancelled') {
// User explicitly cancelled
showMessage('You cancelled the operation')
} else if (error.reason === 'timeout') {
// Timeout occurred
showMessage('Operation timed out. Please try again.')
} else {
// Generic cancellation
showMessage('Operation was cancelled')
}
} else {
// Handle other errors
throw error
}
}

Cleanup After Cancellation

const controller = new AbortController()
let cleanup = null
try {
// Set up resources
cleanup = await setupResources()
const result = await b.FunctionName(input, {
abortController: controller
})
return result
} catch (error) {
if (error instanceof BamlAbortError) {
console.log('Operation cancelled, cleaning up...')
}
throw error
} finally {
// Always cleanup, whether cancelled or not
if (cleanup) {
await cleanup()
}
}

Retry Logic with Abort Errors

async function retryableOperation(input: any, maxRetries: number = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const controller = new AbortController()
try {
// Set timeout for each attempt
setTimeout(() => controller.abort('timeout'), 30000)
return await b.FunctionName(input, {
abortController: controller
})
} catch (error) {
if (error instanceof BamlAbortError) {
if (error.reason === 'timeout' && attempt < maxRetries) {
console.log(`Attempt ${attempt} timed out, retrying...`)
continue
}
// Don't retry for user cancellations
throw error
}
// Don't retry for other errors
throw error
}
}
}

Integration with Streaming

When streaming operations are cancelled, the error behavior differs slightly:

const controller = new AbortController()
const stream = b.stream.FunctionName(input, {
abortController: controller
})
try {
for await (const chunk of stream) {
// Process chunk
if (shouldCancel) {
controller.abort('user_request')
}
}
} catch (error) {
if (error instanceof BamlAbortError) {
// Stream was cancelled
console.log('Stream cancelled:', error.reason)
}
}

Best Practices

1. Always Handle Abort Errors Explicitly

// Good: Explicit handling
try {
await operation()
} catch (error) {
if (error instanceof BamlAbortError) {
// Handle cancellation specifically
return { cancelled: true }
}
// Re-throw unexpected errors
throw error
}
// Bad: Generic error handling
try {
await operation()
} catch (error) {
// All errors treated the same
console.error('Failed:', error)
}

2. Provide Meaningful Cancellation Reasons

// Good: Clear reason
controller.abort('user_clicked_cancel')
controller.abort({ type: 'timeout', duration: 30000 })
// Bad: No reason
controller.abort()

3. Don’t Retry Cancelled Operations

// Good: Check error type before retry
if (error instanceof BamlAbortError) {
// Don't retry - it was intentionally cancelled
return
}
// Bad: Retry everything
for (let i = 0; i < 3; i++) {
try {
return await operation()
} catch (error) {
// This might retry a cancelled operation!
continue
}
}