Troubleshooting Guide
Pick the symptom that matches and jump straight to the first check before you read the deeper route map.
Start with the symptom, not the whole playbook
If this is your first time in Atlas, use this symptom matrix to pick the most likely first move and the next page that will help. You do not need to read the full troubleshooting guide before taking action.
Check source, then role, then initial sync
If you can authenticate and open Atlas but the UI still feels blank, do not start by assuming the app is broken. The fastest triage path is to verify where the data should come from, then whether your role can see it, then whether the system has completed its first sync or bootstrap step.
Observability data unavailable means OpenObserve failed to load on that refresh; cron summary cards showing β or Cron data is partialmean agent responses are missing, not that the underlying job count is zero.Match your symptom to the right first tool β then follow the detailed section below.
Use these triage ladders when you only know the symptom
If you landed here mid-problem, do not read the whole page first. Pick the ladder that sounds closest, run the first check, and only go deeper if that first signal points you there.
The agent went quiet
Open Watchtower and check the last-seen timestamp, then confirm the container is still running.
Recent activity exists and the container is healthy, so the problem is probably upstream delivery or routing rather than a dead process.
Most often this is a crashed container, a wedged gateway, or the message never reaching the agent in the first place.
The request is hanging or feels slow
Look at observability events first and sort by duration so you can find the slow hop before reading logs.
One service clearly stands out as the long pole, which means you can focus on that hop instead of guessing across the whole network.
Slowdowns usually come from one dependency, one overloaded agent, or a wait state that is happening exactly where the trace says it is.
A bridge call failed
Start with the request or correlation ID and trace it across both sides of the bridge before changing anything.
You can see the send event on one side and the receive or auth failure on the other, which tells you whether this is transport, auth, or target-side handling.
The usual culprits are auth mismatches, wrong target routing, or a target agent that accepted the call but failed during execution.
Cron ran at the wrong time
Read the cron expression and timezone together. Most surprises are correct expressions interpreted in the wrong timezone.
You can explain the observed fire time once you convert UTC and local time consistently, which means the schedule is wrong, not the scheduler.
This is usually a UTC vs local-time mismatch, a mistaken daylight-saving assumption, or an expression that means something slightly different than intended.
Pick the lane, then the page
Atlas stays easier to scan when the route map reads like navigation first. Start with the lane that matches your question, then expand the full page-job model only when you need the deeper contract details.
Symptom-first page for named failures, first checks, and practical fixes.
Change pace: Check recent updates first. These pages move when the network or live support surfaces change.
After the symptom is named, jump to the live-status companion or root system to verify what is happening now.
Open Watchtower GuideEntry
Use these pages when you are still orienting and need the safest first click before you pick an owner or system.
Ownership
Use these pages when your real question is who should handle the work, how it moves, or which charter owns the surface.
Systems
Use these pages when you need the map, structure, services, and interfaces behind the network instead of the people or routing rules.
Operations
Use these pages when something feels broken, you need a concrete next check, or you need the live-status companion surface.
Use the route split only after the first troubleshooting move points away from this page
This is a street-level debugging page. Stay here when you already have a symptom and need the fastest check, the most likely cause pattern, or the shortest route to a concrete recovery step.
You already have the symptom
Stay here when the question is how to triage a failure, which first signal to check, or which debugging flow proves the cause.
You need live status, not a playbook
Open Watchtower when you need current activity, recent events, or confirmation that the agent is actually quiet right now.
You still need the owner
Open Capabilities when the real problem is that you do not know which agent should own the next move or which specialist to involve first.
You need the handoff pattern
Open Coordination when the issue is routing, escalation, or how the next message should move between people and agents.
You want the system rationale
Open Architecture when the bug makes more sense once you understand the design boundary, trust model, or why the system behaves this way.
You need one whole trace
Open Workflows when you want to see the full story, from request to handoff to closeout, instead of isolated debugging moves.
Move from signal to proof in three steps
Use the first-run cards or quick diagnostic when you only know what feels wrong.
Jump to the issue block or workflow that matches the failure instead of reading the whole page.
Use the command reference only after you know which system or check you are actually trying to run.
Atlas explains debugging, it does not replace runtime truth
Atlas is still an educational map. This page shows how to reason about failures and where to look next, but it is not the place to confirm live health, restart services, or inspect current metrics directly.
Every interaction leaves a trace
The Saffron Network is designed to be observable. When something goes wrong, the evidence is already there β in logs, observability events, and gateway state. You just need to know where to look.
- Check Watchtower β View recent events and agent activity
- Query the current observability source β Filter the live telemetry stream by service and time to find the failure point
- Inspect agent logs β
docker logs <agent-name>shows crashes, OOM errors, and exceptions - Test in isolation β Call services directly to rule out cascading dependencies
- Follow the chain β Trace requests through Bridge calls using correlation IDs
Common Issues
π¨Agent Not RespondingNo reply or recent activity β check the container, gateway, then the live event trail.βΆ
Symptoms:
- Bridge calls timeout
- No response in Slack/WhatsApp
- Watchtower shows no recent activity
Debugging Steps:
- Check if container is running:
docker ps | grep <agent-name>
- Check container logs:
docker logs --tail 100 <agent-name>
Look for: crashes, OOM errors, unhandled exceptions - Check gateway status:
docker exec <agent-name> openclaw status
- Check live observability events:
curl "<observability-url>/events?service=<agent>&limit=50" \ -H "Authorization: Bearer $OBS_COLLECTOR_TOKEN"
Common Causes:
- Process crashed (check exit code in
docker ps -a) - Out of memory (Docker OOM killer)
- Deadlock or hung request (restart container)
- Gateway config error (check gateway.toml syntax)
Fix:
docker restart <agent-name>
β±οΈBridge Call TimeoutsA bridge waits past its timeout β separate target health, auth, and downstream work.βΆ
Symptoms:
- Error: "Bridge timeout after 60s"
- Caller hangs waiting for response
Debugging Steps:
- Check if target agent is reachable:
curl http://host.docker.internal:<port>/health
- Check live bridge telemetry:
curl "<observability-url>/events?service=bridge&event=call&limit=20" \ -H "Authorization: Bearer $OBS_COLLECTOR_TOKEN"
Look for: long duration_ms values, error-level events - Test the target agent directly:
docker exec <target-agent> openclaw status
Common Causes:
- Target agent is processing a long task (LLM call, tool execution)
- Target agent is stuck in a loop
- Network issue (rare on localhost)
- Target agent's gateway is overloaded (too many concurrent requests)
Fix:
- If agent is busy but healthy: wait or retry later
- If agent is stuck:
docker restart <target-agent> - If happens frequently: increase timeout or optimize target agent's performance
β°Cron Jobs Not RunningThe scheduled job never appears β verify enablement, next run, history, and timezone.βΆ
Symptoms:
- Scout cycle didn't run at expected time
- No Slack notification from scheduled task
- Watchtower cron shows
Cron data is partial - Summary cards show
βplus an all-agents fetch-failed warning instead of counts
Debugging Steps:
- Read the Watchtower state message before the counts:If Watchtower says
Cron data is partial, some agents answered and some did not. If summary cards showβwith an all-agents failure banner, treat the entire summary as unavailable rather than zero. - List all cron jobs:
curl "<gateway-url>/api/cron/list"
Check:enabledfield,nextRuntimestamp - Check job run history:
curl "<gateway-url>/api/cron/runs?jobId=<job-id>"
Look for: error field, completed field - Check gateway logs during scheduled time:
docker logs scout --since 10m
Common Causes:
- Job is disabled (check
enabled: false) - Gateway was down/restarting during scheduled time
- Previous run still executing (won't start concurrent run)
- Cron expression has wrong timezone (default is UTC)
- One or more agent gateways failed to answer the cron list request, so Watchtower can only show partial coverage
Fix:
- Manually trigger:
curl -X POST <gateway-url>/api/cron/run?jobId=<id> - Re-enable: Update job with
enabled: true - Adjust schedule if timezone is wrong
- If Watchtower coverage is partial or unavailable, restore agent/gateway connectivity first, then refresh before trusting the summary cards again
πService UnreachableA service returns connection errors β check health, ports, and the owning gateway.βΆ
Symptoms:
- Error: "ECONNREFUSED" or "Connection refused"
- Memory / knowledge search failing
- OpenObserve or Watchtower observability surface not responding
- Watchtower shows
Observability data unavailable - Code execution requests timing out
Debugging Steps:
- Check if the service process is running:
ps aux | grep <service-name>
- Try a direct health check:
curl http://localhost:<service-port>/health
- If Watchtower named the failure, trust the category:
Observability data unavailablemeans the route loader could not load OpenObserve data on that refresh. Treat it as source-health trouble, not an empty event feed. - Check service logs β look for crash messages or startup errors:
tail -f <service-log-path>
Common Causes:
- Service crashed or was stopped
- Port conflict (another process using the same port)
- Service not restarted after a host reboot
- Upstream OpenObserve connectivity failed, so Watchtower rendered an explicit unavailable state instead of stale empty data
Fix:
Restart the affected service using its startup script. Check the Infrastructure page for each serviceβs expected port and startup method.
πMemory or Performance IssuesA run is slow or crashes β find the long pole before tuning memory or concurrency.βΆ
Symptoms:
- Agent responses getting slower
- Container keeps restarting
- Mac mini fans running loud
Debugging Steps:
- Check container resource usage:
docker stats --no-stream
Look for: high CPU%, high MEM% - Check host resources:
top -o cpu # or htop
- Check disk usage:
df -h docker system df # Docker disk usage
- Check session_status for token usage:
High token counts = expensive operations
Common Causes:
- Memory leak in agent (growing context, cached data)
- Too many concurrent operations
- Large file operations (logs, databases)
- Docker volume running out of space
Fix:
- Restart agent:
docker restart <agent> - Clean up disk:
docker system prune -a - Trim old logs/data from workspaces
- Increase Docker resource limits in Docker Desktop settings
β°Cron Timing Edge CasesThe expression is valid but fires unexpectedly β compare UTC, local time, and daylight saving.βΆ
Symptoms:
- Scout cycle ran an hour early or late (DST shift)
- Cron job fires at UTC midnight instead of local midnight
- Two cycles ran close together then a long gap with no runs
nextRuntimestamp doesn't match expected schedule
Root Cause Patterns:
- Missing timezone: Cron expressions default to UTC. A job meant to run at 8 AM CT needs
tz: "America/Chicago"β without it, it runs at 8 AM UTC (3 AM CT). - DST transitions:
everyMs-based jobs aren't affected by DST, butcron-based jobs are. "0 8 * * *" withtz: "America/Chicago"will correctly shift with DST. - Stagger jitter: Jobs with
staggerMsadd random jitter to the scheduled time β this is intentional to avoid thundering-herd, but makes timing look unpredictable. - Previous run still executing: If a cycle runs long, the next scheduled fire is skipped (no concurrent runs for the same job).
Fix:
- Always set
tzexplicitly on cron-scheduled jobs - Use
cronschedule kind (noteveryMs) when you need wall-clock alignment - Check
/api/cron/runs?jobId=<id>for skipped runs β they show asskipped: true
π§ Session Context OverflowResponses truncate or lose the thread β inspect context pressure and split the work.βΆ
Symptoms:
- Agent responses become truncated, generic, or start repeating earlier context
- Agent forgets instructions given earlier in the session
- Tool calls fail with "context length exceeded" or similar errors
- Model switches to a cheaper fallback unexpectedly
Root Cause Patterns:
- Long-running session: Sessions accumulate context with every message and tool response. A charter cycle that reads many files and makes many edits fills the context window fast.
- Large tool outputs: Reading entire files, getting verbose API responses, or listing large directories bloats the context.
- Repeated full-file reads: Reading the same file multiple times in one session duplicates content in context.
- Sub-agent output: Spawned sub-agents return their full output to the parent session, which can be very large.
Debugging Steps:
- Check session token usage: Use
openclaw statusor the session status card β look for token counts approaching the model's limit. - Review the session transcript: Identify which messages or tool responses are disproportionately large.
- Check if a fallback model was used: Some gateways auto-fallback when context overflows β look for model switch events in logs.
Fix:
- For operators: Start a fresh session or use
limitandoffsetwhen reading files to get only the lines you need - For cycle design: Use
lightContext: trueon cron jobs to reduce inherited context weight - For sub-agents: Request concise summaries rather than full output dumps
- For large files: Read targeted sections with offset/limit instead of entire files
πBranch Merge Conflict During CycleSync-in or push finds overlapping edits β preserve intent, rebase, then verify the affected path.βΆ
Symptoms:
- PR merge blocked by merge conflict
- Git rebase or merge fails during sync-in
- CI fails on a branch that was passing locally
git statusshows "both modified" on files you didn't expect to conflict
Root Cause Patterns:
- Concurrent cycles: Another agent or a manual edit pushed to the same branch or base while this cycle was running.
- Stale working branch: The feature branch fell behind
mainbecause it was created hours or days ago and main has moved forward. - Shared data files: Files like progress logs, scratchpads, or freshness tags are frequently modified by multiple actors β these are the most common conflict points.
- Squash-merge divergence: If main was squash-merged and the branch still has the original commits, git sees them as different and conflicts appear on files touched by both.
Debugging Steps:
- Identify conflicting files:
git diff --name-only --diff-filter=U - Check what changed on main:
git log --oneline main..origin/mainβ were the same files modified? - Decide conflict strategy: For data files (logs, timestamps), newer usually wins. For code, manual resolution is needed.
Fix:
- Rebase onto current main:
git fetch origin && git rebase origin/main - Resolve conflicts: For data files, accept the newer version; for code, merge both changes carefully
- If rebase is too tangled: Create a fresh branch from current main and cherry-pick the relevant commits
- Prevention: Keep branches short-lived β rebase onto main at the start of each cycle
πGateway 502 / Not Ready After RestartThe gateway reports 502 just after restart β allow warm-up, then verify readiness before retrying.βΆ
Symptoms:
- Bridge calls return
502 Bad Gatewayimmediately after a gateway restart - Health endpoint returns 200 but bridge calls still fail
- Cron jobs fail with connection errors for the first 30-60 seconds after restart
openclaw statusshows healthy but tool calls hang or error
Root Cause Patterns:
- Cold-start delay: After a gateway restart, the HTTP server binds quickly but the model client, tool registry, and session store take time to initialize. The health endpoint reports "up" before the system is fully ready.
- Session replay: Long sessions need time to load history before they can accept new messages β calls arriving during replay get rejected.
- Dependency warmup: Tools that connect to external services (database, search index) need their own connection pools established.
- Cron race condition: If a cron job fires during the restart window, it hits the gateway before it's ready and fails β and depending on config, may not retry.
Debugging Steps:
- Check gateway uptime:
docker inspect --format={{.State.StartedAt}} <agent>β was it recently restarted? - Check gateway logs for "ready" message:
docker logs <agent> --tail 30β look for "gateway ready" or "session loaded" entries - Retry after 60 seconds: Most gateways are fully operational within 30-60 seconds of container start
Fix:
- Immediate: Wait 60 seconds and retry β the gateway will be ready
- For cron jobs: Use
staggerMsor a startup delay to avoid firing during the cold-start window - For bridge callers: Implement a retry with backoff (2-3 retries, 10-30 second intervals) for 502 responses
- For operators: Check the gateway's "ready" log line before assuming it's fully operational
πAdvisor Returns 401 / Auth RejectedAn advisor call is rejected β verify the token path, identity, and target scope.βΆ
Symptoms:
- Bridge call returns
401 Unauthorized - Bridge call returns
403 Forbidden - Advisor freshness gate fails with auth error (not timeout)
- Bridge works from one agent but not another
Root Cause Patterns:
- Expired gateway token: Bridge calls authenticate using the gateway token (
gatewayToken). If the target gateway rotated its token, the caller still has the old one. - Missing token in bridge config: The bridge script reads the token from environment or config β if it's unset, the call goes out without auth.
- Wrong gateway URL: If the target gateway moved to a new port or host, the bridge points at the old address.
- Agent allowlist mismatch: Some gateways restrict which agents can bridge in. If the caller's identity isn't in the allowlist, the gateway rejects the connection.
Debugging Steps:
- Check the exact error: 401 = bad/missing token, 403 = authenticated but not authorized
- Verify caller's bridge config: Check
gatewayTokenandgatewayUrlfor the target in the caller's environment - Test target gateway health:
curl http://<target-host>:<port>/health - Compare tokens: The caller's configured token must match the target gateway's current token
Fix:
- Update the caller's bridge config with the current gateway token
- If the target gateway was reconfigured, update the URL in the caller's bridge config
- For allowlist issues: update the target gateway's
agents.allowedAgentsto include the caller
Debugging Workflows
πTrace a Failed RequestFollow one request ID hop by hop until the first missing or failed event appears.βΆ
Scenario: User sent a message to Clawdy, no response.
- Check Watchtower β Recent Activity view
Did Clawdy receive the message? Any errors? - Check Clawdy logs:
docker logs clawdy --tail 50 --timestamps
Look for errors, crashes, unhandled exceptions - Check gateway status:
docker exec clawdy openclaw status
Is gateway healthy? Session active? - Check messaging provider:
WhatsApp/Slack outage? Credential expired? - Test manually:
docker exec -it clawdy bash # Inside container: try openclaw commands
πInvestigate Slow PerformanceSort the trace by duration to isolate the service or wait state causing the slowdown.βΆ
Scenario: Scout cycles taking much longer than usual.
- Check session_status: High token usage? Expensive model calls?
- Query the current telemetry stream:
curl "<observability-url>/events?service=delegation&limit=20" \ -H "Authorization: Bearer $OBS_COLLECTOR_TOKEN" | jq .
Look for duration_ms values β What's taking longest? - Check Codex usage: Is coding-muscle being called excessively?
- Check LLM API latency: Provider issue? (Z.AI or OpenAI status page)
- Profile specific operations: Add timing logs to identify bottlenecks
πDebug Inter-Agent CommunicationCompare send, receive, auth, and response events across both sides of the bridge.βΆ
Scenario: Scout β Advisor call is failing.
- Test bridge connectivity:
docker exec scout bridge call advisor "test message"
- Check bridge observability:
curl "<observability-url>/events?service=bridge&event=call" \ -H "Authorization: Bearer $OBS_COLLECTOR_TOKEN" | jq '.events[] | select(.meta.target=="advisor")'
- Verify target agent gateway is reachable:
# Each agent exposes a health endpoint at its gateway address: curl "http://host.docker.internal:<gateway-port>/health"
See the Infrastructure page for each agentβs gateway port. - Check both agent logs: Caller and callee
- Test with minimal message: Rule out payload size issues
βοΈAtticus Governance IssuesA proposal pauses or rejects unexpectedly β trace the decision and its stated policy reason.βΆ
Scenario: Proposal sent to Atticus received no response, or decision outcome is unexpected.
- Check Atticus gateway is reachable:
curl http://host.docker.internal:<atticus-gateway-port>/health
- Query recent Atticus decisions:
curl "<observability-url>/events?service=atticus&limit=10" \ -H "Authorization: Bearer $OBS_COLLECTOR_TOKEN" | jq .
Look for decision.made or decision.escalated events and their reasoning. - Check if escalated to Jake: If Atticus returned
needs-human, check#atticus-digestin Slack for the escalation notification. - Review the proposal against policies: See Governance Policies β was the proposal clearly in-scope? Boundary cases often get escalated rather than auto-approved.
- Check Atticus logs:
docker logs atticus --tail 50 --timestamps
Quick Reference: Debugging Commands
Docker
docker ps β Running containersdocker ps -a β All containers (including stopped)docker logs <name> β View logsdocker logs -f <name> β Follow logs (live)docker restart <name> β Restart containerdocker exec -it <name> bash β Enter container shelldocker stats β Resource usageOpenClaw
openclaw status β Gateway healthopenclaw gateway start β Start gatewayopenclaw gateway stop β Stop gatewayopenclaw gateway restart β Restart gatewayObservability Collector
Cron Jobs
β οΈ When to Escalate to Humans
- System-wide outage: Multiple agents down, can't be resolved by restart
- Data loss: Missing files, corrupted databases, deleted content
- Security concerns: Unexpected network activity, suspicious logs
- Infrastructure changes needed: New services, port changes, credential rotation
- Persistent performance degradation: Issues that reoccur after fixes
For these situations, notify Jake/Derek in Slack with: what's wrong, what you tried, and what you need.