Skip to main content
The same image can produce very different machines. Declare what you need at creation time instead of maintaining a derived image for each variation.

What you can set

The fields below are forwarded through **kwargs to the underlying BoxOptions in wrapper classes such as SimpleBox/CodeBox, and can also be used directly with BoxOptions(...).
SimpleBox’s convenience parameters only cover image / rootfs_path / memory_mib / cpus / runtime / name / auto_remove / reuse_existing; env / entrypoint / cmd / user / working_dir and so on are forwarded through **kwargs to BoxOptions, so their names and types follow BoxOptions (for example Python’s working_dir, and the construction-time env being a list of tuples).

Quick Example

The shortest path: use SimpleBox to inject environment variables, run as a non-root user, set the working directory, and then run a command to verify.
Node equivalent:

The relationship between entrypoint and cmd

An OCI image has two directives: ENTRYPOINT (the executable) and CMD (default arguments). The final startup command is the concatenation of the two: ENTRYPOINT + CMD.
  • Set only cmd: replace the default arguments, keep the image’s ENTRYPOINT.
  • Set only entrypoint: replace the executable.
  • Set both: fully customize the startup behavior.
Note: some images (such as python:alpine) put the default command in CMD rather than ENTRYPOINT. To pass arguments like -c, you must explicitly set entrypoint=["python3"], otherwise the arguments have nothing to attach to.
Important: entrypoint + cmd controls the container init process. If that init command is short-lived (it exits as soon as it finishes, e.g. python3 -c "print(...)"), the container enters the Stopped state after init exits, and you can no longer call box.exec(...); it raises RuntimeError: internal error: spawn_failed: Container init process exited — cannot exec. ... incompatible container status: \Stopped“. Therefore: if you want to customize init via entrypoint + cmd and also keep exec-ing afterward, init must be a long-lived process (such as sleep or a service process). The example below changes init to time.sleep(120), after which exec reliably returns exit=0. If you only run one command and never exec again, a short-lived init is also fine.

user: running as non-root

user accepts a username or a UID, in the format <name|uid>[:<group|gid>]. Non-numeric usernames are resolved from the container’s /etc/passwd / /etc/group.
You can also override the user/directory/environment per-exec (env here is a dict):

Return value: ExecResult

box.exec(...) returns an ExecResult (a dataclass in the Python wrapper layer). Node’s ExecResult fields are exitCode / stdout / stderr.

Troubleshooting

Passing a string as the volume’s third element causes a TypeError

A volume’s third element is the boolean read_only; the strings "ro"/"rw" are CLI-only and raise TypeError here. See Volumes.

Construction-time env passed as a dict reports a type error (Python)

SimpleBox(env=...) / BoxOptions(env=...) requires list[tuple[str, str]] at construction time:
box.exec(env=...) uses a dict at execution time. The distinction: a list at construction time, a dict at exec time.

cmd arguments take no effect / the image has no ENTRYPOINT

If the image’s default command is in CMD (not ENTRYPOINT), setting cmd=["-c", ...] alone leaves the arguments with no executable to attach to. Explicitly set entrypoint=["python3"] (or the target executable); see the entrypoint example above.

After setting entrypoint + cmd to a short-lived command, exec reports incompatible container status: Stopped

entrypoint + cmd is the container init process. A short-lived init (which exits as soon as it finishes) puts the container into the Stopped state, and a subsequent exec raises:
Fix: if you need to keep exec-ing, make init long-lived (sleep / a service); if you only run one command, use a short-lived init and do not exec again. See the entrypoint example above.

working_dir pointing to a nonexistent directory makes exec raise RuntimeError

working_dir (or exec(cwd=...)) must be a directory that already exists in the image. When it points to a nonexistent directory (e.g. setting working_dir="/work" on alpine), the box still creates successfully, but the first exec raises:
Fix: use a directory that ships with the image (alpine has /tmp, /root), or create one first via exec from an existing working directory:

exec exits non-zero without raising

This is expected behavior: when exec fails (the command returns non-zero) it does not raise but returns an ExecResult with exit_code != 0. Always check result.exit_code (Node: result.exitCode).

A missing command / image pull failure raises a standard exception

  • Missing command: raises a standard RuntimeError (Python) / a bare Error (Node), not a BoxliteError subclass.
  • Image pull network flakiness: raises a RuntimeError, which you can retry after try/except.
When catching, use a broad except Exception rather than only catching BoxliteError.

No hardware virtualization causes startup failure

BoxLite requires hardware virtualization (an environment constraint):
  • Linux: requires KVM (/dev/kvm available); under WSL2 the user must be in the kvm group.
  • macOS: uses Apple Hypervisor.framework, no /dev/kvm required (macOS arm64 supported).
  • No virtualization: startup fails on async with entry. The process does not crash and can be caught with try/except to report the issue.