Skip to main content

Start here

The fastest path is the built-in debug skill: open Claude Code in your NanoClaw folder and run /debug. It knows the two-DB session architecture, the log locations, and how to query the session databases directly. If you’re diagnosing by hand, check the logs first. The service writes stdout to logs/nanoclaw.log and stderr (warnings and errors) to logs/nanoclaw.error.log:
Set LOG_LEVEL=debug (see Configuration) to also see resolved mount configurations and streamed container stderr tagged with the container name. Containers run with --rm, so the host log is the only place container output survives. Then get the system state from the ncl CLI:

Host won’t start

“NanoClaw stopped: update did not go through the supported path” — the upgrade tripwire fired. The code version doesn’t match the marker in data/upgrade-state.json, which usually means you ran a raw git pull instead of /update-nanoclaw. See Upgrading for the recovery path. “Circuit breaker: delaying startup due to repeated crashes” in the log — the host crashed repeatedly and is backing off (up to 15 minutes after six consecutive crashes). It will retry on its own; find the original crash in logs/nanoclaw.error.log (look for FATAL Uncaught exception) and fix that instead of restarting in a loop.

”FATAL: Container runtime failed to start”

On startup the host runs docker info. If it fails, NanoClaw prints this banner and exits:
Do exactly what it says: start Docker (Docker Desktop on macOS, sudo systemctl start docker on Linux), confirm docker info succeeds, then restart NanoClaw.

Agent never replies

Trace the message through the pipeline, in order:
1

Did the router accept it?

Each row aggregates drops per chat, with a reason:
2

Did a container spawn?

stopped is normal between messages — the sweep restarts the container when due messages arrive. If nothing spawns at all, see Container won’t spawn below.
3

Did the agent produce a reply?

Inspect the session DBs (inbound.db / outbound.db under data/v2-sessions/<group>/<session>/). The /debug skill walks you through the exact queries. A Container exited non-zero warning in the host log carries the exit code and a stderrTail — the last ~10 lines of container stderr — which is where a boot failure usually shows. A session that ends without a failure, or whose container died after starting, logs Session ended at info level (with the exitCode when it is known); any other failure logs Session failed at error level with a kind and whether it is retryable.

Container won’t spawn

The first two of these abort the spawn; a rejected mount only degrades it (the container starts without that mount). All three appear in logs/nanoclaw.error.log:
  • wakeContainer failed — host-sweep will retry — the host couldn’t set up the credential gateway session (or another spawn step failed), so it didn’t launch the agent. The err field in the log line says why, for example Gateway session admission is closed: ... when the gateway is unavailable. The message stays pending and the sweep retries every minute; fix the gateway connection (is OneCLI reachable at the URL in ONECLI_URL in .env?) and the spawn recovers on its own. See Credentials.
  • Egress lockdown errors — with lockdown enabled, the spawn fails fast rather than run with open egress: the "<network>" internal network could not be created or gateway target "<container>" could not be attached to "<network>". Check docker network inspect for the egress network and see Hardening.
  • Additional mount REJECTED — a mount from your group’s container config failed allowlist validation. The log line includes the requestedPath and reason. Fix the allowlist — see Hardening.

Replies are slow

  • Cold start: the first reply after a container spawn takes 30–60 seconds while the sandbox warms up. Setup tells you this during its ping test; it’s normal.
  • Scheduled or retried messages wait for reconciliation: a periodic resync checks active sessions roughly once a minute, and message writes or container-exit events can trigger earlier checks. Queue work and container cold starts add latency; one minute is not a strict upper bound. Look for Waking container for due messages in the log.
  • Retries back off: a message reset after a crash retries with exponential backoff (5s, 10s, 20s, …). After five tries you’ll see Message marked as failed after max retries — that message is dead; resend it.

Container killed mid-task

The host sweep kills containers it considers stuck, then resets their in-flight messages to pending:
  • Killing container past absolute ceiling — the container’s heartbeat file went silent for longer than the ceiling (30 minutes by default; the line’s ceilingMs field shows the value in effect), and the kill and retry lines after it carry reason absolute-ceiling. The ceiling stretches automatically when the agent declares a longer Bash timeout, so long-running commands aren’t killed as long as they declare their timeout.
  • Killing container — message claimed then silent — the container claimed a message and showed no sign of life since the claim for longer than the claim tolerance (60 seconds by default, also extended by a declared Bash timeout; the line’s toleranceMs field shows the value in effect), and the lines after it carry reason claim-stuck.
Both paths are self-healing: messages the container was still holding are reset, Reset stale message with backoff follows in the log, and they retry in a fresh container, until a message runs out of tries and is marked failed (see above). Messages that arrived later, while the container’s query was still open (mid-turn or after an earlier reply), were marked done when they were handed to the agent, so they are not retried. If the same message keeps killing containers, look at the streamed container stderr (LOG_LEVEL=debug) to see what the agent was doing when it died. If a slow model is being killed in the middle of normal work, raise the timer that fired (settings added after v2026.10.0), in milliseconds, in .env or the service environment, then restart the host:
  • NANOCLAW_ABSOLUTE_CEILING_MS (default 1800000) — the one a slow model usually hits. Every event the agent reports refreshes the heartbeat, so this fires when the model stays silent for a long stretch, for example while it loads or reads a long prompt.
  • NANOCLAW_CLAIM_STUCK_MS (default 60000) — only covers the time between picking up a message and the agent’s first event. Messages that arrive while the container’s query is open are marked done as soon as they are handed to the agent, so a slow model after a later message does not trip it.
Raising one does not raise the other. Values outside the allowed range (1 minute to 24 hours for the ceiling, 10 seconds to 24 hours for the claim timer) or that are not whole numbers are logged as Ignoring NANOCLAW_… and the default is used. See Configuration.

Webhook channel is silent

Webhook-based adapters (Slack, Teams, and similar) register routes on a shared local HTTP server. Confirm it’s up and routed:
The server listens on WEBHOOK_PORT (default 3000). If another process already holds that port, the listen fails, the host logs Webhook server error and keeps running without a webhook listener, so webhook channels stay silent while everything else works. WEBHOOK_PORT is read from the process environment first, then from .env (src/config.ts:121), so set it in .env or in the service definition, then restart. A value that is not an integer from 1 to 65535 is rejected at startup. Channel-specific failures (tokens, tunnel/public URL, platform-side config) are covered on each channel page: Slack, Teams, Channels overview.

Credential request stuck

If an agent’s API call hangs and then fails, a credential approval card may be waiting. The gateway holds the request open until an admin taps Approve or Reject; with no eligible approver it auto-denies, and unanswered cards expire. Check what’s pending:
The full approval flow — who gets the card, expiry, what happens after a host restart — is in Credentials.

Recovering a misbehaving session

Start with /debug in Claude Code and identify the session with ncl sessions list. Do not delete a session directory while its host or container is using it: a running container may still hold the mounted databases, and the host also tracks durable runtime state. Back up the install before any destructive recovery. Restarting a group with ncl groups restart --id <group-id> replaces its running containers while preserving conversation data.

Template agent replies 401 or 403

Expected on first use, not a fault. A template ships no credentials, so the first call to a service the vault has no key for fails. The agent replies with a prefilled connect link for that host — open it, paste the key, and ask it to retry. The template’s own README.md lists the services it expects and how to connect them.

Template task never fires

Template tasks are created paused on purpose, so stamping never starts background work without consent. Nothing fires until you resume them:
If a task is already resumed and still quiet, it’s a normal scheduling problem rather than a template one — see Scheduled tasks.

Restamping reports “Nothing to apply”

Restamping reads only your local templates/ copy, and nothing refreshes it for you. Update the local folder first — edit it if you authored it, or re-download the registry copy — then re-run. See Updating a stamped agent.

Getting help

  • Run /debug in Claude Code — it can read the logs and query the session DBs for you.
  • Join the Discord for help from other users.
  • Open an issue if you’ve found a bug.
Last modified on October 19, 2026