nanobot troubleshooting table
Corresponding source
| Failure boundary | Source |
|---|---|
| Entry points and configuration | nanobot/cli/commands.py, nanobot/config/loader.py, nanobot/config/paths.py |
| Agent Loop and Runner | nanobot/agent/loop.py, nanobot/agent/runner.py |
| Provider retry/fallback | nanobot/providers/base.py, nanobot/providers/fallback_provider.py |
| Tool discovery/validation | nanobot/agent/tools/loader.py, nanobot/agent/tools/registry.py |
| Session and atomic persistence | nanobot/session/manager.py |
| Channel/API/WebUI | nanobot/channels/, nanobot/api/server.py, nanobot/webui/, webui/src/ |
Five diagnostic questions
Answer these five questions first:
- Did the request reach the entry point? Did CLI, API, or Channel actually construct a request?
- Is this the intended Session? Do the actual Session key and workspace match expectations?
- At which layer did it stop? AgentLoop state, Runner, Provider, Tool, Channel, or UI?
- What does each kind of evidence establish? What do logs, state trace, Runtime Events, Session files, and wire frames each prove?
- What is the smallest reproduction? Can you remove WebUI, the real Channel, or unnecessary Tools?
flowchart LR A["Entry point"] --> B["AgentLoop"] B --> C["AgentRunner"] C --> D["Provider / Tool"] B --> E["Session"] B --> F["Outbound / Event"] F --> G["Channel / API / SDK / WebUI"]
Common symptoms
| Symptom | First boundary to inspect | Evidence to examine | Common causes | Next step |
|---|---|---|---|---|
| Command will not start | CLI and configuration loading | traceback, actual configuration path, Python environment | missing dependency, configuration parse failure, missing ${VAR}, occupied port | Run minimal nanobot --help or status, then inspect nanobot/config/loader.py |
| DeepSeek returns 401/403 | Provider credentials | HTTP status and active Provider; never print the key | variable absent from this process, invalid key, wrong Provider selected | Check only that DEEPSEEK_API_KEY exists, then verify preset and Provider |
| Provider returns 429/5xx | Provider retry and fallback | retry log, _retry_wait, final error | rate limiting, transient outage, unsuitable retry policy | Distinguish retry from fallback; read providers/base.py and fallback_provider.py |
| Request never ends | Runner and timeout layers | state trace, last delta, timeout name | Tool did not return, idle stream, persistent Goal, outer LLM timeout | Separate API timeout, LLM timeout, and stream-idle timeout |
| Tool is absent from the model schema | Tool discovery and Registry | registered Tool list and loader logs | undiscovered module/entry point, name collision, invalid instance, scope mismatch | Inspect loader.py and test_tool_loader_* |
| Tool is called but arguments fail | Tool schema | arguments and validation error | mismatch between parameters and execution signature, invalid required/type/additional fields | Reproduce with tests adjacent to ToolRegistry.prepare_call() or Tool.validate_params() |
| Tool succeeds but the model does not see the result | Runner feedback | tool-result message, call ID, truncation metadata | serialization failure, call-ID mismatch, result over character limit | Inspect AgentRunner’s Tool-result assembly |
| MCP fails to start | Transport connection | command or URL, stderr, connection logs | Windows command normalization, wrong cwd/env, service not running, SSRF block | Verify the stdio process or HTTP endpoint independently, then read mcp.py |
| MCP connects but exposes no Tools | enabledTools and registration | server Tool list and wrapped names | enabledTools=[], name allowlist mismatch, incomplete initialization | Compare raw names with wrapped mcp_<server>_<tool> names |
| New message cannot see old context | Session key and replay | actual key, Session JSONL, loaded messages | changed Channel/chat, override, unified Session, compaction or history limit | Inspect session/keys.py and SessionManager |
| Session file is corrupted or incomplete | SAVE | temporary file, original file, persistence-error log | process failure, disk error, non-atomic path, incorrect concurrent use | Preserve evidence and do not overwrite manually; inspect atomic-save tests |
Context is wrong after /stop | Cancellation and checkpoint | cancellation logs, checkpoint, end of Session | cancellation at Tool/Provider boundary, restore failure | Inspect test_task_cancel.py and test_stop_preserves_context.py |
| CLI works but Channel does not reply | Outbound delivery | OutboundMessage, ChannelManager retry logs | Channel configuration or credentials, bad routing, platform API failure | Isolate core with a direct call or fake Channel |
| Final reply exists but streaming progress does not | Hook and Channel configuration | callback presence and metadata | missing _wants_stream, sendProgress=false, no Channel delta implementation | Inspect progress_hook.py and the Channel’s send_delta() |
| Streamed content is duplicated or merged incorrectly | Segments and coalescing | _stream_id, _stream_end, sequence | merged segments, replayed deltas, faulty UI reducer | Trace from WebSocket frame through React state |
| WebUI remains “running” | Runtime Event and WebSocket | TurnRunStatusChanged, TurnCompleted, frame | completion not published, subscriber failure, bad disconnect/replay state | Confirm core finished, then inspect coordinator and adapter |
| Configuration changed but behavior did not | Configuration to runtime snapshot | actual loaded path, active preset and model | wrong file, preset override, no refresh/restart, bad alias | Use the configuration index |
| File Tool rejects a path outside workspace | Workspace policy | resolved path and access mode | restrictToWorkspace, path escape, or symlink check | Do not bypass it; determine whether the task should remain inside workspace |
| Sandbox is configured on Windows but commands are not isolated | OS sandbox | startup warning, sandbox Provider and enforced flags | bwrap path depends on Linux/container support; Windows lacks this execution boundary | Treat it as unsandboxed; use an external container/VM or lower-privilege environment |
| Web fetch is denied | SSRF | URL, resolved IP, redirect chain | localhost/private/reserved address, DNS result, or blocked redirect | Do not disable global protection; add only a reviewed, minimal trusted CIDR |
| Memory does not change | Memory and trigger conditions | Memory files, Tool Call, Dream/Cron logs | no Memory Tool invocation, Dream disabled/not triggered, wrong workspace | Distinguish Session history from Memory |
| Cron does not trigger | Scheduling and timezone | job store, next run, timezone, status | disabled job, wrong timezone, Gateway not persistent, protection rule | Inspect CronService independently before changing AgentRunner |
Minimum isolation order
WebUI problem
→ Verify core with SDK or direct call
→ Inspect Runtime Event or progress callback
→ Inspect WebSocket frame
→ Inspect React state last
Channel problem
→ Verify Provider and Agent with CLI or direct call
→ Construct one InboundMessage
→ Inspect OutboundMessage
→ Contact the real platform last
Tool problem
→ Instantiate the Tool directly
→ Validate its schema
→ Execute through ToolRegistry
→ Trigger a Tool Call with a fake Provider
→ Make a real-model smoke test lastAvoid these diagnostic mistakes
- Do not paste keys, complete configurations, or credential-bearing URLs into logs.
- Do not begin with WebUI, a real Channel, MCP, and several Tools all enabled.
- Do not start editing frontend components merely because an error appears in the UI.
- Do not use infinite retry to hide authentication, schema, or deterministic logic failures.
- Do not disable workspace or SSRF protection to make a test pass.
- Do not edit a Session file and then continue treating it as evidence of the original failure.
When evidence remains insufficient
Record explicitly:
- minimum input;
- entry point and Session key, without sensitive values;
- final AgentLoop state;
- active Provider and model;
- whether a Tool Call occurred;
- last observable event;
- whether a fake Provider or direct call reproduces it.
Then return to Logging, Runtime Events, and testing strategy to choose the next evidence layer.
Return to Quick reference.