Troubleshooting
Start with drydock doctor; it smoke-tests the sandbox setup (image freshness,
VM boot, the egress pin) with no API spend. Then consult the table below.
Check a repo before submitting
drydock doctor --repo <path> preflights one local repo without booting a
container or spending API budget: repo size against the per-task stage cap,
language toolchains against what the sandbox image ships (node/python/go),
package-registry hosts (defaults plus any custom registry in
.npmrc/.yarnrc/Cargo.toml/pip.conf) against your egress allowlist, and
repo files that collide with diff_policy.blocked_paths /
second_look_paths. Warnings are advisory (the task can run but will likely
hit friction); a red FAIL is a blocker — a task on that repo is guaranteed to
fail — and the command exits 1. Run it before the first drydock submit
against an unfamiliar repo.
Common failures
| Symptom | First place to look |
|---|---|
192.168.66.1 never became bindable |
container ls -a (is the anchor running?), container network inspect drydock-egress (gateway IP present?) |
Image build COPY fails: failed to calculate checksum … not found on a file that exists on disk |
Apple container ships an empty build context when the context path traverses a symlink. Fixed in v0.5.1 (drydock resolves the path); if you hit it on an older build, run container build against the real path (readlink -f the image dir). |
Image build dies at apt-get: Temporary failure resolving 'deb.debian.org' |
In-VM DNS is broken because the host's resolvers are loopback proxies (Cloudflare WARP, dnscrypt, some VPNs) the VM can't reach. scutil --dns shows only 127.x in resolver #1. Fix: container builder delete --force && container builder start --dns 1.1.1.1, then rebuild. drydock doctor warns when it detects this. |
Image build fails on npm install |
Transient registry timeout; rerun container build (or make image) |
| Squid CONNECT 403 to an expected host | cat ~/.drydock/squid/squid-default-acl.conf; add it in egress.yaml or per-task with --egress-extra (see Egress) |
| Stale anchor after a crash | container rm -f drydock-anchor; the next drydock start does this for you |
| Gateway 401 | Key is wrong or a placeholder (sk-ant-fake is expected to 401) |
502 credential unavailable on a subscription task |
The subscription token expired and the refresh failed. brokerd auto-refreshes and (as of the self-heal fix) reloads a token rotated in by another process; if it persists, the refresh token itself is dead; run drydock auth claude (or codex) to re-authenticate. |
| VM reaches a host it shouldn't | Confirm init-firewall.sh ran inside the VM; overriding --entrypoint skips it |
no usable agent credential at start |
No API key in env / api-keys.env, and no *_auth: subscription set; see Authentication |
| Subscription task errors after spinning | A task_max_requests cap was hit (HTTP 429); the agent retries with backoff before exiting; see Authentication |
A config.yaml edit or env var isn't taking effect |
drydock policy explain — the SOURCE column shows which layer (default / config.yaml / env:VAR) actually won for each setting, and the daemon verdict at the bottom catches the other classic cause: brokerd resolves its policy once at boot, so a DIVERGENT verdict means the running daemon predates your change — restart brokerd to pick it up. See Configuration. |
push preflight failed (auth) at submit |
drydock proved it cannot push to the repo before the sandbox even booted, so nothing was spent. Two fixes: for HTTPS remotes, run gh auth setup-git to install a credential helper; for SSH remotes, load a key into your agent (or point GIT_SSH_COMMAND at one) so it's usable non-interactively. drydock doctor now surfaces this generically as the git push credentials check, though it's a heuristic (it doesn't know your task's target repo); the submit-time preflight is the real, per-repo gate. |
Where to look
- Per-task agent output (stream-json):
~/.drydock/audit/<id>.jsonl, follow live withdrydock logs <id> -f. - The captured diff:
~/.drydock/audit/<id>.diff. - An egress-widening request awaiting approval:
~/.drydock/audit/<id>.widen.json.
Housekeeping
The sandbox image picks up Debian security fixes on each rebuild: apt-get upgrade runs in the Dockerfile before the package install block, so any
build triggered by drydock setup brings the image current. The daily CVE
scan in CI (image-scan) rebuilds the image and gates on any unfixed CVEs.
To stay current locally, re-run drydock setup periodically; the daily scan
flags anything outstanding.
The audit directory has no automatic retention. Delete old artifacts with:
drydock prune --older-than 720h --keep-last 50 # dry-run unless you add --yes