| title | FAQ |
|---|---|
| description | Frequently asked questions and troubleshooting guide for BoxLite. |
| icon | circle-question |
Frequently asked questions and common issues with BoxLite.
BoxLite is a local-first micro-VM sandbox for AI agents — think "SQLite for sandboxing." It's a library you embed directly in your application, no daemon or cloud account required. Unlike ephemeral sandboxes that destroy state after each execution, BoxLite Boxes are stateful workspaces — install packages, create files, build up environment state, then come back later and pick up where you left off. | Feature | BoxLite | Docker | |---------|---------|--------| | **Isolation** | Hardware VM (KVM/Hypervisor.framework) | Container (namespaces/cgroups) | | **Daemon** | No daemon required | Requires Docker daemon | | **Root** | No root required | Typically needs root/sudo | | **Architecture** | Local-first library | Client-server architecture | | **Default state** | Stateful by default — full filesystem persists across stop/restart | Ephemeral by default — needs explicit volumes to persist data | | **Use Case** | AI agent sandboxes, secure code execution | Application deployment, CI/CD | | **Startup** | ~1-2 seconds | ~100-500ms | | **Isolation Level** | Separate kernel, hardware isolation | Shared kernel |**When to use BoxLite:**
- AI agents that need full execution freedom
- Untrusted code execution
- Hardware-level isolation required
- Embedded in applications (no daemon)
**When to use Docker:**
- Application deployment
- Development environments
- CI/CD pipelines
- Established Docker workflows
**macOS:** Hypervisor.framework is available to all users (no special permissions).
**Linux:** Only requires access to `/dev/kvm`, which can be granted through group membership:
```bash
sudo usermod -aG kvm $USER
# Logout and login for changes to take effect
```
**Requirements:**
- Windows 10 version 2004+ or Windows 11
- WSL2 with a Linux distribution (Ubuntu recommended)
- KVM support enabled in WSL2
**Setup:**
```bash
# Inside WSL2, add your user to the kvm group
sudo usermod -aG kvm $USER
# Apply the new group membership (pick one):
newgrp kvm
# OR restart WSL from Windows PowerShell:
# wsl.exe --shutdown
# Verify KVM access
python3 -c "open('/dev/kvm','rb').close(); print('kvm ok')"
```
**Common Issue:** If you see "Timeout waiting for guest ready (30s)" errors, your shell cannot open `/dev/kvm`. This happens when:
- `/dev/kvm` is owned by `root:kvm` with mode `660`
- Your user is not in the `kvm` group
Run `sudo usermod -aG kvm $USER` and restart WSL with `wsl.exe --shutdown`.
<Note>
Native Windows (without WSL2) is not supported. BoxLite requires KVM (Linux) or Hypervisor.framework (macOS).
</Note>
Check your version:
```bash
python --version # Should be 3.10+
```
Upgrade if needed:
```bash
# macOS (Homebrew)
brew install python@3.11
# Ubuntu/Debian
sudo apt install python3.11
# Or use pyenv
pyenv install 3.11.0
```
**Production considerations:**
- Stable API
- Hardware-level isolation
- Resource limits enforced
- Error handling robust
- Monitor resource usage
- Test at expected scale
- Configure appropriate limits
See the [AI Agent Integration](/guides/ai-agent-integration) guide for production configuration, concurrency, and security patterns.
**Linux:** KVM (Kernel-based Virtual Machine)
**How it works:**
- BoxLite uses libkrun as the hypervisor abstraction
- libkrun provides a unified API over Hypervisor.framework (macOS) and KVM (Linux)
- Each box runs as a separate microVM with its own kernel
**Default:** 2048 MiB
**Range:** 128 MiB to 64 GiB (65536 MiB)
**Overhead:**
- VM overhead: ~50-100 MB per box
- Guest kernel: ~20-40 MB
- Container: Depends on image
**Example:**
```python
# Lightweight box
boxlite.BoxOptions(memory_mib=128) # Minimum for Alpine
# Standard box (default)
boxlite.BoxOptions(memory_mib=2048) # Default
# Heavy box
boxlite.BoxOptions(memory_mib=4096) # For complex workloads
```
**Factors:**
- Image size (cached vs first pull)
- Disk I/O speed
- Available resources
**First run:** 5-30 seconds (includes image pull)
**Subsequent runs:** 1-2 seconds (image cached)
**Optimization:**
- Pre-pull images: `runtime.create(boxlite.BoxOptions(image="..."))`
- Reuse boxes instead of creating new ones
- Use smaller base images (`alpine:latest` vs `ubuntu:latest`)
**Ephemeral (default):**
```python
boxlite.BoxOptions() # Data lost when box is removed
```
**Persistent:**
```python
boxlite.BoxOptions(
disk_size_gb=10 # 10 GB persistent QCOW2 disk
)
# Data survives stop/restart
await box.stop()
# ... later ...
box = runtime.get(box_id) # Disk intact
```
**Also:**
- Use volume mounts for host-box data sharing
- Read-write volumes persist changes to host filesystem
**2. Check box status:**
```python
info = box.info()
print(f"State: {info.state}")
```
**3. Inspect filesystem:**
```bash
# Check disk space
df -h ~/.boxlite
# Check box data
ls -la ~/.boxlite/boxes/
# Check image cache
ls -la ~/.boxlite/images/
```
**4. Check hypervisor:**
```bash
# Linux
ls -l /dev/kvm
lsmod | grep kvm
# macOS
sw_vers # Should be 12+
uname -m # Should be arm64
```
See the [macOS Sandbox Debugging](/guides/macos-sandbox-debugging) guide for comprehensive troubleshooting.
**Outbound connections:**
- HTTP/HTTPS requests
- DNS resolution
- Any protocol (TCP/UDP)
**Example:**
```python
async with boxlite.SimpleBox(image="alpine:latest") as box:
# Test internet access
result = await box.exec("wget", "-O-", "https://api.github.com/zen")
print(result.stdout)
```
```python
boxlite.BoxOptions(
ports=[
(8080, 80, "tcp"), # Host 8080 -> Guest 80
(5432, 5432, "tcp"), # PostgreSQL
(53, 53, "udp"), # DNS (UDP)
]
)
```
**Access from host:**
```bash
curl http://localhost:8080
```
See the [Architecture: Networking & Storage](/architecture/networking-storage) page for details.
**Alternatives:**
1. **Share data via volumes:**
```python
volumes=[("/host/shared", "/mnt/shared", False)] # False = read-write
```
2. **Use host network:**
Box A exposes a port, and Box B connects to `host.docker.internal:port` (or localhost on Linux).
3. **External service:**
Both boxes connect to Redis/database on host or network.
1. **Insufficient resources:**
```python
# Increase limits
boxlite.BoxOptions(
cpus=4, # More CPUs
memory_mib=4096, # More memory
)
```
2. **Disk I/O:**
- Use ephemeral storage (faster than QCOW2)
- Check host disk speed: `dd if=/dev/zero of=test bs=1M count=1024`
3. **Too many boxes:**
```python
metrics = await runtime.metrics()
print(f"Running boxes: {metrics.running}")
# Reduce concurrency or increase host resources
```
4. **Image size:**
- Use smaller images: `alpine:latest` (5 MB) vs `ubuntu:latest` (77 MB)
- Check image size: `docker images`
**Resource calculation:**
```text
Total Memory = (boxes * memory_mib) + overhead
Total CPUs = boxes * cpus (can oversubscribe)
Example:
100 boxes * 512 MiB = 51.2 GB memory needed
100 boxes * 1 CPU = 100 CPUs (oversubscribed, shares-based)
```
**Best practices:**
- Start small (10 boxes) and scale up
- Monitor metrics: `runtime.metrics().active_boxes`
- Use resource pooling (reuse boxes)
- Test at expected load
**Example:**
```python
import asyncio
async def run_100_boxes():
tasks = []
for i in range(100):
task = run_box(i)
tasks.append(task)
results = await asyncio.gather(*tasks)
```
**Memory:**
- Range: 128 MiB to 64 GiB (65536 MiB)
- Limited by host RAM
**Disk:**
- Range: 1 GB to 1 TB
- Limited by host storage
**CPUs:**
- Range: 1 to host CPU count
- Can oversubscribe (shares-based)
**Tested configurations:**
- 64 GiB memory
- 1 TB disk
- 16 CPUs
**Solutions:**
```bash
# Test with Docker first
docker pull <image>
# Check network
ping registry-1.docker.io
# For private images, authenticate
docker login
# Check image name format
# Correct: "python:3.11-slim"
# Wrong: "python/3.11-slim"
# Clear cache if corrupted
rm -rf ~/.boxlite/images/*
```
**Debug:**
```bash
RUST_LOG=debug python script.py
# Look for image-related errors in output
```
1. **Check disk space:**
```bash
df -h ~/.boxlite
# Should have at least 1 GB free
```
2. **Verify hypervisor:**
```bash
# Linux
ls -l /dev/kvm
lsmod | grep kvm
# macOS
sw_vers | grep ProductVersion # Should be 12+
uname -m # Should be arm64
```
3. **Check image:**
```bash
docker pull <image>
# Should succeed
```
4. **Enable debug logging:**
```bash
RUST_LOG=debug python script.py
```
5. **Check permissions:**
```bash
# Linux: Ensure user in kvm group
groups | grep kvm
# If not, add and relogin
sudo usermod -aG kvm $USER
```
**Symptom:** Box creation fails with "Timeout waiting for guest ready (30s)" or "VM subprocess exited before guest became ready" on Ubuntu 24.04. Works with `sudo` or on Ubuntu 25.04+.
**Root Cause:** Ubuntu 24.04 restricts unprivileged user namespaces via AppArmor (`kernel.apparmor_restrict_unprivileged_userns=1`) but does not ship the `bwrap-userns-restrict` profile that Ubuntu 25.04+ includes. bwrap (bubblewrap) needs user namespaces for sandbox isolation.
**Diagnosis:**
```bash
# Check for AppArmor denials
dmesg | grep apparmor
# Look for: apparmor="DENIED" ... comm="bwrap" capability=8
# Check if bwrap profile exists
aa-status | grep bwrap
# Should show "bwrap-userns-restrict" if profile is installed
```
**Fix (Option A -- targeted, recommended):**
Install the bwrap AppArmor profile that Ubuntu 25.04+ ships. Create the file `/etc/apparmor.d/bwrap-userns-restrict` with the following content, then reload:
```bash
sudo tee /etc/apparmor.d/bwrap-userns-restrict << 'PROFILE'
abi <abi/4.0>,
include <tunables/global>
profile bwrap /usr/bin/bwrap flags=(attach_disconnected,mediate_deleted) {
allow capability,
allow file rwlkm /{**,},
allow network,
allow unix,
allow ptrace,
allow signal,
allow mqueue,
allow io_uring,
allow userns,
allow mount,
allow umount,
allow pivot_root,
allow dbus,
allow pix /** -> &bwrap//&unpriv_bwrap,
include if exists <local/bwrap-userns-restrict>
}
profile unpriv_bwrap flags=(attach_disconnected,mediate_deleted) {
allow file rwlkm /{**,},
allow network,
allow unix,
allow ptrace,
allow signal,
allow mqueue,
allow io_uring,
allow userns,
allow mount,
allow umount,
allow pivot_root,
allow dbus,
allow pix /** -> &unpriv_bwrap,
audit deny capability,
include if exists <local/unpriv_bwrap>
}
PROFILE
sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict
```
**Fix (Option B -- quick, less secure):**
Disable the restriction globally:
```bash
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
# To persist across reboots:
echo "kernel.apparmor_restrict_unprivileged_userns=0" | \
sudo tee /etc/sysctl.d/99-boxlite-userns.conf
```
**Fix (Option C -- disable jailer):**
If you don't need sandbox isolation (e.g., development environment), disable the jailer:
```python
from boxlite.boxlite import SecurityOptions
boxlite.BoxOptions(
security=SecurityOptions(jailer_enabled=False),
# ... other options
)
```
**Solutions:**
```python
import asyncio
# Add timeout
async def execute_with_timeout():
execution = await box.exec("command")
try:
result = await asyncio.wait_for(
execution.wait(),
timeout=30 # 30 second timeout
)
return result
except asyncio.TimeoutError:
await execution.kill()
print("Command timed out")
```
**Check if command needs input:**
```python
# Provide stdin if needed
execution = await box.exec("command")
stdin = execution.stdin()
await stdin.send_input(b"input\n")
```
1. **Check port is not in use:**
```bash
lsof -i :8080
# Should be empty, or show boxlite process
```
2. **Verify configuration:**
```python
# Correct
ports=[(8080, 80, "tcp")]
# Wrong (swapped)
# ports=[(80, 8080, "tcp")] # Don't do this
```
3. **Test from inside box:**
```python
# Start server in box
await box.exec("python", "-m", "http.server", "80", background=True)
# Test from host
import requests
response = requests.get("http://localhost:8080")
```
4. **Check gvproxy:**
```bash
ps aux | grep gvproxy
# Should show gvproxy process
ls ~/.boxlite/gvproxy/
# Should contain gvproxy binary
```
**1. ~/.boxlite directory:**
```bash
chmod 755 ~/.boxlite
chown -R $USER ~/.boxlite
```
**2. /dev/kvm (Linux):**
```bash
# Check permissions
ls -l /dev/kvm
# Should be: crw-rw---- 1 root kvm
# Add user to kvm group
sudo usermod -aG kvm $USER
# Logout and login required
# Or temporarily (not recommended)
sudo chmod 666 /dev/kvm
```
**3. Volume mounts:**
```bash
# Ensure host path is accessible
chmod 755 /host/path
```
**Solutions:**
1. **Increase memory limit:**
```python
boxlite.BoxOptions(
memory_mib=2048, # Increase from 512 to 2048
)
```
2. **Check actual usage:**
```python
# metrics() is available on the low-level Box object (via runtime.create())
metrics = await box.metrics()
print(f"Memory: {metrics.mem / (1024**2):.2f} MB")
```
3. **Optimize code:**
- Reduce memory footprint of executed code
- Process data in chunks instead of loading all at once
- Clear variables when no longer needed
**Solutions:**
1. **Load KVM module:**
```bash
sudo modprobe kvm kvm_intel # For Intel CPUs
sudo modprobe kvm kvm_amd # For AMD CPUs
# Verify
lsmod | grep kvm
```
2. **Check CPU support:**
```bash
grep -E 'vmx|svm' /proc/cpuinfo
# Should show vmx (Intel) or svm (AMD)
```
3. **Enable in BIOS:**
- Reboot and enter BIOS/UEFI
- Enable "Intel VT-x" or "AMD-V"
- Save and reboot
4. **Add user to kvm group:**
```bash
sudo usermod -aG kvm $USER
# Logout and login
```
**Solutions:**
1. **Check macOS version:**
```bash
sw_vers
# ProductVersion should be 12.0 or higher
```
2. **Check architecture:**
```bash
uname -m
# Should output: arm64 (Apple Silicon)
```
3. **Upgrade if needed:**
- BoxLite requires macOS 12+ (Monterey or later)
- Apple Silicon (M1, M2, M3, M4) only
- Intel Macs are **not supported**
<Note>
If you have an Intel Mac, consider using a Linux VM, deploying to cloud (AWS, GCP, Azure), or using a cloud-based sandboxing service.
</Note>
**Community:**
- [Discord](https://go.boxlite.ai/discord) -- Chat with the team and community
- [GitHub Issues](https://github.com/boxlite-ai/boxlite/issues) -- Bug reports and feature requests
- [GitHub Discussions](https://github.com/boxlite-ai/boxlite/discussions) -- Questions and community support
**Before posting:**
1. Check this FAQ
2. Search existing issues/discussions
3. Enable debug logging: `RUST_LOG=debug`
4. Include BoxLite version, platform, and minimal reproduction
**2. Gather information:**
- BoxLite version: `python -c "import boxlite; print(boxlite.__version__)"`
- Platform: `uname -a`
- Python version: `python --version`
- Error message and stack trace
**3. Minimal reproduction:**
```python
import asyncio
import boxlite
async def reproduce():
# Minimal code that reproduces the issue
async with boxlite.SimpleBox(image="python:slim") as box:
result = await box.exec("command")
asyncio.run(reproduce())
```
**4. Debug logs:**
```bash
RUST_LOG=debug python reproduce.py 2>&1 | tee debug.log
```
**5. Create issue:**
- Use bug report template
- Include all gathered information
- Attach debug logs if relevant
- Be specific and clear
**Areas to contribute:**
- Bug fixes
- Documentation improvements
- New examples
- SDK improvements (Python, Node.js, C)
- Performance optimizations