Skip to main content
BoxLite provides a structured exception hierarchy for error handling and metrics classes for monitoring resource usage across boxes.

Error Types

from boxlite import BoxliteError, ExecError, TimeoutError, ParseError

Exception Hierarchy

BoxliteError (base)
├── ExecError       # Command execution failed
├── TimeoutError    # Operation timed out
└── ParseError      # Output parsing failed

BoxliteError

Base exception for all BoxLite errors. Catch this to handle any BoxLite-specific error.
try:
    async with SimpleBox(image="invalid:image") as box:
        pass
except BoxliteError as e:
    print(f"BoxLite error: {e}")

ExecError

Raised when a command execution fails (non-zero exit code).
AttributeTypeDescription
commandstrThe command that failed
exit_codeintNon-zero exit code
stderrstrStandard error output
try:
    result = await box.exec("false")  # Exit code 1
except ExecError as e:
    print(f"Command: {e.command}")
    print(f"Exit code: {e.exit_code}")
    print(f"Stderr: {e.stderr}")

TimeoutError

Raised when an operation times out.
try:
    await computer.wait_until_ready(timeout=5)
except TimeoutError:
    print("Desktop did not become ready in time")

ParseError

Raised when output parsing fails.
try:
    x, y = await computer.cursor_position()
except ParseError:
    print("Failed to parse cursor position")

Core Error Variants

BoxLite uses a centralized error enum internally. These are surfaced as BoxliteError exceptions in Python with descriptive messages.

UnsupportedEngine

Platform or hypervisor not supported. Cause:
  • Running on Windows
  • Running on Intel Mac
  • KVM not available on Linux
  • Hypervisor.framework not available on macOS
Example:
Error: unsupported engine kind
Solution:
  • Use supported platform (macOS ARM64, Linux x86_64/ARM64)
  • Verify hypervisor availability:
    • Linux: grep -E 'vmx|svm' /proc/cpuinfo
    • macOS: Ensure macOS 12+ on Apple Silicon

Engine(String)

Hypervisor or VM engine error. Cause:
  • KVM module not loaded
  • Insufficient permissions for /dev/kvm
  • Hypervisor.framework error
  • VM creation failed
Example:
Error: engine reported an error: KVM is not available
Solution:
# Linux: Load KVM module
sudo modprobe kvm kvm_intel  # or kvm_amd

# Linux: Check /dev/kvm permissions
ls -l /dev/kvm
sudo chmod 666 /dev/kvm

# Linux: Add user to kvm group
sudo usermod -aG kvm $USER
# (logout and login required)

Config(String)

Invalid box configuration. Cause:
  • Invalid CPU count (< 1 or > host CPUs)
  • Invalid memory size (< 128 or > 65536)
  • Invalid paths in volumes
  • Invalid port numbers
Example:
Error: configuration error: CPU count must be between 1 and 8
Solution:
  • Verify configuration parameters are within valid ranges
  • Check file paths exist for volume mounts
  • Ensure port numbers are valid (1-65535)

Storage(String)

Filesystem or disk operation error. Cause:
  • Disk full (~/.boxlite partition)
  • Permission denied writing to ~/.boxlite
  • Disk image creation failed
  • QCOW2 operation failed
Example:
Error: storage error: No space left on device
Solution:
# Check disk space
df -h ~/.boxlite

# Check permissions
ls -ld ~/.boxlite
chmod 755 ~/.boxlite

# Clean up old boxes
# (manually remove ~/.boxlite/boxes/*)

Image(String)

OCI image pull or extraction error. Cause:
  • Network connectivity issues
  • Invalid image name or tag
  • Registry authentication required
  • Image not found in registry
  • Corrupted image layers
Example:
Error: images error: failed to pull image: 404 Not Found
Solution:
# Verify image exists
docker pull <image>

# Check network connectivity
ping registry-1.docker.io

# Authenticate for private images
docker login

# Clear image cache if corrupted
rm -rf ~/.boxlite/images/*

Portal(String)

Host-guest communication error (gRPC over vsock). Cause:
  • Guest agent not responding
  • vsock connection failed
  • gRPC timeout
  • Guest initialization failed
Example:
Error: portal error: connection timeout
Solution:
  • Enable debug logging: RUST_LOG=debug
  • Check if box is running: box.info().status
  • Restart box: box.stop() and recreate
  • Report issue with logs if persists

Network(String)

Network configuration or connectivity error. Cause:
  • gvproxy not running or crashed
  • Port already in use
  • Network backend initialization failed
Example:
Error: network error: bind: address already in use
Solution:
# Check port availability
lsof -i :8080

# Stop conflicting process or use different port
ports=[(8081, 80, "tcp")]

# Verify gvproxy binary exists
ls ~/.boxlite/gvproxy/

Execution(String)

Command execution error. Cause:
  • Command not found in image
  • Command crashed or killed
  • Execution timeout
  • Streaming I/O error
Example:
Error: Execution error: command not found: python3
Solution:
  • Verify command exists in image:
    result = await box.exec("which", "python3")
    
  • Check exit code and stderr:
    result = await box.exec("command")
    if result.exit_code != 0:
        print(f"Failed: {result.stderr}")
    

Internal(String)

Internal BoxLite error. Cause:
  • Unexpected internal state
  • I/O error
  • JSON parsing error
  • Unhandled edge case
Example:
Error: internal error: unexpected state transition
Solution:
  • Enable debug logging: RUST_LOG=debug python script.py
  • Report issue with full logs to GitHub
  • Include BoxLite version, platform, and reproduction steps

NotFound(String)

Box or resource not found. Cause:
  • Box ID does not exist
  • Box was removed
  • Image not in cache
Example:
Error: box not found: 01JJNH8...
Solution:
  • List all boxes: runtime.list()
  • Verify box ID is correct
  • Create new box if needed

AlreadyExists(String)

Box or resource already exists. Cause:
  • Duplicate box creation attempt
  • Port already forwarded
Example:
Error: already exists: box with this ID exists
Solution:
  • Use existing box: runtime.get(box_id)
  • Remove existing box: box.remove()
  • Use different configuration (e.g., different port)

InvalidState(String)

Box is in wrong state for requested operation. Cause:
  • Executing command on stopped box
  • Stopping already stopped box
  • Restarting box that never started
Example:
Error: invalid state: cannot execute on stopped box
Solution:
  • Check box status: info = await box.info(); print(info.status)
  • Restart box if stopped: runtime.get(box_id) (may auto-restart)
  • Create new box if needed

Error Handling Patterns

Basic Error Handling

import boxlite

async def safe_execution():
    try:
        async with boxlite.SimpleBox(image="python:slim") as box:
            result = await box.exec("python", "script.py")

            # Check exit code
            if result.exit_code != 0:
                print(f"Command failed: {result.stderr}")
                return

    except Exception as e:
        # All BoxLite errors are raised as Python exceptions
        print(f"Error: {e}")

        # Enable debug logging for details
        # RUST_LOG=debug python script.py

Catching Specific Errors

from boxlite import SimpleBox, BoxliteError, ExecError, TimeoutError

async def handle_errors():
    try:
        async with SimpleBox(image="python:slim") as box:
            result = await box.exec("python", "-c", "import nonexistent")
    except ExecError as e:
        print(f"Execution failed (exit {e.exit_code}): {e.stderr}")
    except TimeoutError:
        print("Operation timed out")
    except BoxliteError as e:
        print(f"BoxLite error: {e}")
    except Exception as e:
        print(f"Unexpected error: {e}")

Retry Pattern

import asyncio
from boxlite import SimpleBox, BoxliteError

async def with_retry(max_retries=3):
    for attempt in range(max_retries):
        try:
            async with SimpleBox(image="python:slim") as box:
                result = await box.exec("python", "-c", "print('success')")
                return result.stdout
        except BoxliteError as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt  # Exponential backoff
                print(f"Attempt {attempt + 1} failed, retrying in {wait_time}s...")
                await asyncio.sleep(wait_time)
            else:
                raise

Metrics

boxlite.RuntimeMetrics

Aggregate metrics across all boxes managed by a runtime instance.
FieldTypeDescription
boxes_createdintTotal boxes created
boxes_destroyedintTotal boxes destroyed
total_exec_callsintTotal command executions
active_boxesintCurrently running boxes
runtime = Boxlite.default()
metrics = await runtime.metrics()

print(f"Boxes created: {metrics.boxes_created}")
print(f"Boxes destroyed: {metrics.boxes_destroyed}")
print(f"Total exec calls: {metrics.total_exec_calls}")
print(f"Active boxes: {metrics.active_boxes}")

boxlite.BoxMetrics

Per-box resource usage metrics. Retrieved via box.metrics().
FieldTypeDescription
cpu_time_msintTotal CPU time in milliseconds
memory_usage_bytesintCurrent memory usage in bytes
network_bytes_sentintTotal bytes sent
network_bytes_receivedintTotal bytes received
metrics = await box.metrics()

print(f"CPU time: {metrics.cpu_time_ms}ms")
print(f"Memory: {metrics.memory_usage_bytes / (1024**2):.2f} MB")
print(f"Network sent: {metrics.network_bytes_sent} bytes")
print(f"Network received: {metrics.network_bytes_received} bytes")

Monitoring Example

import asyncio
from boxlite import SimpleBox

async def monitor_box():
    async with SimpleBox(image="python:slim") as box:
        # Start a workload
        execution = await box.exec("python", "-c", """
import time
data = []
for i in range(100):
    data.append('x' * 10000)
    time.sleep(0.1)
""")

        # Monitor metrics while running
        for _ in range(10):
            metrics = await box.metrics()
            print(f"CPU: {metrics.cpu_time_ms}ms | "
                  f"Memory: {metrics.memory_usage_bytes / (1024**2):.1f} MB | "
                  f"Net TX: {metrics.network_bytes_sent} | "
                  f"Net RX: {metrics.network_bytes_received}")
            await asyncio.sleep(1)

        await execution.wait()

Runtime-wide Monitoring

from boxlite import Boxlite, BoxOptions

async def runtime_monitoring():
    runtime = Boxlite.default()

    # Create several boxes
    boxes = []
    for i in range(3):
        box = await runtime.create(BoxOptions(image="alpine:latest"))
        boxes.append(box)

    # Check runtime metrics
    metrics = await runtime.metrics()
    print(f"Active boxes: {metrics.active_boxes}")
    print(f"Total created: {metrics.boxes_created}")

    # Clean up
    for box in boxes:
        await box.stop()

    # Check again
    metrics = await runtime.metrics()
    print(f"Active boxes: {metrics.active_boxes}")
    print(f"Total destroyed: {metrics.boxes_destroyed}")

See Also