Troubleshooting
Fixes for the problems you are most likely to hit while installing or running agents-sandbox.
Note: Run
agents-sandbox doctorfirst. It checks the host prerequisites and reports what is missing; the sections on this page cover the cases it cannot resolve on its own.
agents-sandbox doctor fails
If the doctor command reports missing prerequisites:
Container engine not running
Start your container engine. agents-sandbox talks to it over the Docker API, so what matters is that the engine serves that API, not which vendor provides it:
- Tested — Docker Engine, Docker Desktop, colima, podman.
- Expected to work, but untested — Podman Desktop and macOS podman machines, Rancher Desktop, OrbStack, Lima, and any other engine that exposes a Docker-compatible socket.
- Not supported — an engine with no Docker API, such as bare containerd with
nerdctl, or colima started with itscontainerdruntime.
podman only: one podman setting can stop a build that works everywhere else, see The base image cannot be found.
How you start the engine depends on which one you use:
- Docker Desktop (macOS, Windows) starts from Applications. A Docker Engine installed as a system-wide package
on Linux starts with
sudo systemctl start docker. - colima (macOS) starts with
colima start. - podman serves its API from a socket you start yourself. On Linux rootless, enable the user socket with
systemctl --user enable --now podman.socket; podman then listens on$XDG_RUNTIME_DIR/podman/podman.sock, so point the launcher at it withexport DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock. On macOS, start the podman VM withpodman machine start, then point the launcher at the socket it reports:export DOCKER_HOST="unix://$(podman machine inspect --format '')". Installingpodman-mac-helperinstead makes the default/var/run/docker.sockwork.
Both DOCKER_HOST exports are per shell: add the line to your shell profile so the launcher keeps finding podman.
Verify the engine is up and serving the Docker API with docker info (Docker, colima) or podman info (podman). It
should show a healthy daemon.
The launcher finds the Docker endpoint the same way the docker CLI does: DOCKER_HOST first, then the active docker
context (docker context ls), then the default /var/run/docker.sock. An engine that publishes its socket through a
docker context, such as colima or Docker Desktop, needs no extra configuration; point DOCKER_HOST at an engine that
publishes none.
BuildKit vs the classic builder
Which builder the image build uses depends on the engine. Docker Engine, Docker Desktop, colima, and the untested
OrbStack, Rancher Desktop (moby mode), and Lima build with BuildKit; podman (including the untested Podman Desktop and
macOS podman machines) uses the classic builder. BuildKit-only Dockerfile features — RUN --mount=..., cache mounts,
a # syntax directive — build on the Docker engines and fail on podman with a parse error from the classic builder;
heredoc RUN support depends on the podman version (4.8 or newer).
Microsandbox runtime
agents-sandbox provisions its own private microsandbox runtime under its data
directory (~/.local/share/agents-sandbox/msb, or
$XDG_DATA_HOME/agents-sandbox/msb) and points the SDK at it. The runtime never
reads or writes your own ~/.microsandbox; the one-time upgrade migration reads
it only to copy your old volumes (see Upgrading to 0.6).
It does not install a user-facing msb command, and does not require any
particular msb version on your machine. If agents-sandbox is the only thing
installed, the absence of an msb command is expected, not a defect.
“database schema is newer than this msb binary”
A newer agents-sandbox upgraded the runtime’s data, and this version’s bundled runtime cannot read it. This happens
after a downgrade. Upgrade with agents-sandbox upgrade, or run the newer binary. If you switched from a canary back to
an older stable release, agents-sandbox upgrade reports that you are up to date; run
agents-sandbox upgrade --channel canary instead.
If you encounter a runtime error, submit a bug report at:
https://github.com/inoio/agents-sandbox/issues/new?template=bug_report.yml
Legacy home volumes after upgrading
For the upgrade overview — what changed, the migration choices, and how to retire
~/.microsandbox — see Upgrading to 0.6. See
Private volumes with unclear status for diagnosing an interrupted or unclear copy.
An interrupted copy resumes where it stopped, because progress is tracked in
agents-sandbox’s host state. If a private volume already exists under a legacy
name — for example after ~/.local/state/agents-sandbox/state.yaml was removed —
its status is unclear; Private volumes with unclear status covers that case.
Private volumes with unclear status
The offer says so, cannot tell whether such a volume is a complete copy or a partial one, and gives two options:
- Copy the missing volumes; dismiss the existing private volumes from the migration — copies only the absent volumes and leaves the existing ones untouched and never asked about again.
- Quit — if you want a specific volume fully migrated, remove its private
copy with
agents-sandbox volume remove --force <name>(the copy is still referenced by its project’s state, hence--force), then run again: the next offer will re-copy it from the legacy home. Keep the copies you do not want migrated.
KVM unavailable
# Check if /dev/kvm exists
ls -la /dev/kvm
If missing, enable virtualization in your system BIOS/UEFI (INTEL-VT, AMD-V or similar) and ensure your user is in the kvm group:
sudo usermod -aG kvm "$USER"
Log out and back in for the group change to take effect.
macOS-specific issues
Not Apple Silicon
The doctor command will exit with an error if you are running the x86_64 binary under Rosetta 2. Download the darwin-arm64 binary instead. To check your current architecture:
uname -m
Expected output on supported hardware: arm64.
Docker socket not found
On macOS the engine runs inside a VM, so the socket comes from whichever engine you started. Verify it is running:
docker info
If Docker Desktop is installed but not running, launch it from Applications. If using colima:
colima start
If using podman, start its VM and point the launcher at the socket it reports:
podman machine start
export DOCKER_HOST="unix://$(podman machine inspect --format '')"
agents-sandbox finds the socket the same way the docker CLI does: DOCKER_HOST wins, then the active
docker context, then the default /var/run/docker.sock. If docker info works but agents-sandbox reports
the socket as unreachable, check which context is active and where it points:
docker context ls
A context marked * that points at a stopped provider explains the failure — switch it with
docker context use <name>, or point agents-sandbox at the socket directly:
export DOCKER_HOST=unix://$HOME/.colima/default/docker.sock
Note that DOCKER_HOST takes precedence over the active context, so an outdated value in your shell
profile overrides a correct context.
VM won’t start
When a VM won’t start, check the general troubleshooting steps first.
“create sandbox: …” errors
Try --log-level verbose to see the full error:
agents-sandbox run --log-level verbose
Common causes:
- Not enough system memory — reduce with
-m 2G
State file errors
agents-sandbox keeps host state in YAML files under ~/.local/state/agents-sandbox/: one launcher-global state.yaml
and one state.yaml per project and agent. It never overwrites a state file it cannot read.
“state file was written by a newer agents-sandbox”
A newer agents-sandbox wrote the file with a schema this version does not know. To keep that version’s data intact,
this version refuses to change the file. Upgrade with agents-sandbox upgrade, or run the newer binary.
“parse root state file … run agents-sandbox state repair”
The launcher-global state.yaml is corrupt, which blocks update checks, the runtime migration, and identity adoption.
Run agents-sandbox state repair to move it aside as
state.yaml.corrupt-<timestamp>. The next run starts from a fresh launcher state.
Stale sandboxes consume resources
A sandbox that is no longer in use is stopped by its idle policy and reclaimed by auto-pruning. To list, stop, or
reclaim sandboxes by hand, see Sandboxes for the list, stop, kill, and prune commands.
Worktree session issues
“failed to create worktree”
If the managed worktree creation fails, retry the command. If the problem persists, check for uncommitted changes or locked worktrees:
git worktree list
A stale guest worktree keeps its registration in the host checkout’s git dir even after the session ends, so check the
host too. Do not run git worktree prune on the host while any guest worktree exists — the host sees every live
guest worktree as prunable (its gitdir file points into the VM), so the command removes all their registrations at
once and orphans their commits. Remove the stale entry from inside the VM instead, for example in a
shell session with git worktree remove <path> (add --force if the worktree has
uncommitted changes), where <path> is the worktree’s guest directory as reported by git worktree list — guest
worktrees live under ~/.local/share/opencode/worktree/. A host git worktree prune is appropriate only once the
guest worktree itself is gone, for example after its home volume was deleted.
Worktree prompt hangs
If the worktree creation prompt doesn’t respond, check that the repository has a remote configured:
git remote -v
Without a remote, some git operations may hang. Add one or use an absolute branch name:
git remote add origin https://example.com/repo.git
Missing tools inside the sandbox
If you need a tool that isn’t in the base image (e.g., go, rustc, python3), add it to your project’s custom Dockerfile, see Runner Image documentation.
Opencode plugins do not load in the sandbox
opencode and opencode2 only: a local plugin or custom tool that imports an npm package works on your machine but not
in the sandbox, and the opencode log in the VM shows failed to load plugin ... Cannot find package. The packages in
~/.config/opencode/node_modules are not copied into the VM. Install them inside the VM as described in
Install Opencode Plugin Dependencies.
Secrets not available
Verify the secret is set with the correct format. For legacy env.secret, the format is KEY=value@host where the
part after the last @ is the host policy tag — values may contain @. If no @host part is present the
secret is dropped with a warning.
For env.secret.yaml, values may contain @ without issues. Ensure the entry defines either host, hosts, or
allow_any_host_dangerous: true — entries with no hosts definition are silently skipped. An empty value is valid
and passed through unchanged.
Forbidden: Request blocked by network policy
The VM’s network policy does not allow the destination. An HTTP client to a resolved-but-denied destination receives a
403 whose JSON body names the blocked domain:
{"code":"network_policy_denied","message":"Request blocked by network policy.","domain":"api.example.com"}
Denied HTTPS is closed at the TCP connection instead — curl exits with code 7 and no body arrives — except on a port
microsandbox’s TLS proxy intercepts: a configured secret turns TLS interception on, and there the denial is the same
403 delivered in-tunnel (the connection completes against the interception CA, which the guest trusts). See TLS
certificate errors for one application. Under the none profile, a name
the policy does not allow does not resolve (NXDOMAIN) before any egress, so there is no 403 at all.
Other protocols see the connection fail instead. Allow the destination with egress-allow, or pick a profile that
covers it (private for your local network, host for a service on the host); see
Networking.
Forbidden: Request blocked by secret policy
The proxy refused to forward a request that carried a secret placeholder. Two causes produce the same message: the
placeholder reached a host the secret is not allowed for, or it reached an allowed host over plain HTTP, where the
proxy cannot substitute it — substitution only happens on a TLS-terminated connection (see
Placeholders in request bodies). For the first
cause, add the host the application actually calls to the secret’s host/hosts. For the second, make the
application use HTTPS. A common case is GitHub Copilot on GitHub Enterprise, where OpenCode calls the enterprise
domain instead of api.githubcopilot.com; see
GitHub Copilot on GitHub Enterprise.
TLS certificate errors for one application
Once a secret is configured, requests to the matching hosts go through microsandbox’s TLS proxy, whose interception CA
the guest system store trusts. An application with its own trust store does not, and fails with a certificate-path
error — Java reports
SunCertPathBuilderException: unable to find valid certification path to requested target. Import the CA into that
store with the msb-trust helper from the runner image:
agents-sandbox shell --root
msb-trust java
See Trusting the CA in applications for which applications already work, and the Java recipe for the boot hook that repeats the import after a recreate.
Memory or CPU limits too low
If the agent runs slowly or VMs fail to start with resource errors, increase allocation:
agents-sandbox run -c 4 -m 8G
Or set defaults in config:
# ~/.config/agents-sandbox/config.yaml
cpus: 4
memory: 8G
The launcher also detects an out-of-memory kill and offers to raise memory for you; see
Launcher configuration.
Config not applying
If your config files aren’t being picked up:
-
Verify the file exists in the right location:
ls ~/.config/agents-sandbox/config.yaml ls .agents-sandbox/config.yaml -
Check valid syntax:
# For YAML files python3 -c "import yaml; yaml.safe_load(open('config.yaml'))" # For JSON/JSONC files python3 -c "import json; json.load(open('config.json'))" -
Check that CLI flags aren’t overriding your config (flags always win).
-
Check that the project config is approved: a changed
.agents-sandbox/is ignored until you approve it (see “project config change requires approval”). -
Use
--log-level verboseto see which config files were loaded:agents-sandbox run --log-level verbose
“project config change requires approval”
A run without a terminal found a change in .agents-sandbox/ that you have not approved, so it did not start. Run
agents-sandbox once in a terminal in the same checkout, review the listed changes, and choose Approve. See
Approving project config changes.
The warning “the project config changed and is not approved, so it is ignored for this command” has the same cause: that command ran without your project config.
“project config changed since it was approved”
A file in .agents-sandbox/ (or a file home: copies from the checkout) changed after you approved the project
config and before the run used it, often because the agent in a running sandbox edited it. The run stopped before
it started the sandbox and did not build an image from a changed Dockerfile, so the sandbox never saw the changed
file. Run agents-sandbox again: it shows the change and asks for approval.
Image build fails
Docker build failures are usually due to:
-
Network issues — The base image downloads packages from the internet. Ensure outbound access:
curl -fsSL https://debian.org | head -c 100If the failure is apt’s
returned a non-zero code: 100, see Package downloads fail. -
Docker daemon memory — Large builds may need more memory:
docker info | grep "Total Memory" -
Custom Dockerfile errors — If using a project Dockerfile, build it manually to isolate the issue:
docker build -f .agents-sandbox/Dockerfile -t test-image .
If an older image or updater state reports Release vuser-provided not found, update agents-sandbox and rebuild the
runner image. user-provided identifies an agent that was previously found in a custom base; it is not a valid release
version. A rebuilt image will keep an agent supplied by the base, or install a real resolved release if that binary is
no longer present.
Package downloads fail with “returned a non-zero code: 100”
100 is apt’s general error code. When the build log also shows Temporary failure resolving ...,
Some index files failed to download, or Failed to fetch, the build could not reach its package mirror. The build
runs on your host’s engine, so a broken or IPv6-only resolver there causes this. agents-sandbox prints the failing
step’s last output after such an error, so the apt message appears in the failure.
Reproduce it outside agents-sandbox:
docker run --rm debian:trixie-slim apt-get update
If that also fails, give the engine a working resolver. Add one to your Docker Engine’s daemon.json and restart the
engine:
{ "dns": ["1.1.1.1", "8.8.8.8"] }
This applies to both builders agents-sandbox uses, and it is the fix for the managed step that installs the base tools
(the one that failed in the example), which you cannot edit. If only the IPv6 path is broken and the failing apt-get
is one you wrote in your project Dockerfile, ask apt to use IPv4 there instead: add -o Acquire::ForceIPv4=true to
each apt-get line in that Dockerfile.
apt already retries a transient failure three times, so raising Acquire::Retries rarely helps. On apt-get update,
a W: line marks a failure apt tolerates; the build then fails in the apt-get install step that follows.
The base image cannot be found
If the build fails before it runs any of your steps because the engine could not find an image named in a FROM, the
engine is being asked to resolve a name with no registry in it. agents-sandbox pulls its own base under its full name
(docker.io/library/debian:trixie-slim), so that name comes from your project Dockerfile or from a base it starts from.
Docker Engine assumes Docker Hub and never fails this way; podman does when it has no search registries:
Error: short-name "debian:trixie-slim" did not resolve to an alias and no unqualified search
registries are defined in "/etc/containers/registries.conf"
Either fix works: name the registry in the FROM, such as FROM docker.io/library/debian:trixie-slim, or tell podman
which registry to search by adding it to registries.conf:
unqualified-search-registries = ["docker.io"]
short_name_mode = "permissive" on its own does not help while that list is empty.
When the build reports base image not found or not logged in for a name that already carries a registry, the registry
rejected the pull instead: the image does not exist, it is private, or you are not logged in to it. The registry’s own
message follows, such as pull access denied, unauthorized: …, or denied: …. Fix the name and retry, or log in to
that registry (docker login <registry>) before building again.
A base image in a private registry (Artifactory, GitHub Container Registry, a company mirror) needs no manual
docker pull. The launcher sends the registry credentials the docker CLI would use: it reads the Docker CLI config
(~/.docker/config.json, or the directory DOCKER_CONFIG names), including a credsStore such as desktop.exe on WSL
or osxkeychain on macOS and per-registry credHelpers. If docker pull <image> works in your shell, the build can
pull the image too.