services/openclaw/troubleshooting.md

OpenClaw Troubleshooting

ClawdHub CLI Error (undici)

If you see ERR_MODULE_NOT_FOUND for "undici":

npm install -g undici

Gateway Not Responding

openclaw gateway restart
openclaw doctor

Gateway crash loop after upgrading to 2026.9.8

Observed 2026-10-02 after npm install -g openclaw@latest && openclaw gateway install --force:

  • LaunchAgent repeatedly exited with code 78 (EX_CONFIG); port 18789 was not listening.
  • Startup logs said agent databases used schema version 23 and required session-identity migration.
  • Fix: openclaw doctor --fix --non-interactive. Doctor stopped the managed Gateway, saved SQLite backups alongside each database (*.pre-startup-migration-<id>.bak), migrated all four agent databases from v23 to v24, and restored the Gateway service.
  • Allow several minutes for Doctor to finish. In this repair it outlived a 120-second command timeout and continued successfully; do not start a second repair while the original process is still running.
  • Verify with openclaw gateway status: version 2026.9.8, connectivity probe OK. Dashboard HTTP returned 200 and database integrity verification passed.
  • Remaining warnings were separate from this startup failure: official-plugin version drift, unfinished Codex data/settings upgrade, and providers.deepseek.apiKey validation in the captured model catalog.
  • openclaw gateway stop may refuse unless --force is supplied; Doctor's repair flow handled the stop itself.

Your skill folders are symlinks pointing outside the skills root. Fix it by adding that target root to skills.load.extraDirs in ~/.openclaw/openclaw.json, then restart the Gateway. See Skill symlinks & external skill roots in skills.md. Note: skills.load.allowSymlinkTargets does not fix this in 2026.9.5.

Frequent Compaction / Context Overflows

If you're hitting compaction every few turns (especially with heavy tool use):

Config settings (applied May 2026):

  • Default model switched to DeepSeek V4 Flash (1M context window vs old 64k)
  • Compaction mode: default with 200k reserve tokens
  • These together should give ~10-20x more time between compactions

API Key Leaked in Notes

If you accidentally commit or paste API keys in notes, rotate the key in the provider's console and update the notes file. The DeepSeek key was previously exposed here — rotate it if needed.

Talk / voice mode keeps asking to confirm read-only work

Talk-mode (voice) runs gate high-impact actions behind a spoken "yes". Classification lives in dist/tool-mutation-*.mjs (isMutatingToolCall); the gate lives in src/talk/client-voice-confirmation[-policy].ts.

  • Code-mode exec (a JS payload, no command field) is always treated as mutating, even when it only calls read-only tools.
  • A plain read-only shell command is exempt (ls, grep, cat, head, rg, gh reads, read-only sed).
  • A spoken confirmation is bound to one exact tool fingerprint, is single-use, expires in ~120s, and is scoped to agentId + voiceSessionId + runId. Re-issuing the command mints a new confirmation id, which is why a repeated action looks "stuck".
  • There is no config toggle for this gate.

Fix: read-only work (web search, memory recall, notes lookup, file reads) must call the read-only tools directly (web_search, memory_search, read, sessions_search), never wrapped in code-mode exec. Enforced by an AGENTS.md rule and by the local readonly-guard plugin (below).

Verified caveat (2026-09-27): the plugin only helps on typed/non-voice runs. In a voice-bound run the spoken-confirmation gate is evaluated on the client path ahead of server-side before_tool_call hooks, so readonly-guard cannot intercept it: wrapping a read-only lookup in code-mode exec during Talk still returns VOICE_CONFIRMATION_REQUIRED. The real enforcement in Talk is the AGENTS.md rule (call the read-only tools directly) plus asking for one confirmation and holding, never re-issuing.

New local plugins need a Gateway restart to load

Installing, enabling, or reloading a local plugin does not get it into the running Gateway process. All of these report success, and openclaw plugins inspect <id> --runtime even shows Status: loaded, but the live process does not dispatch the plugin's hooks until the Gateway is restarted:

openclaw plugins install --link <dir> --force
openclaw plugins enable <id>
openclaw plugins reload <id>
  • Symptom: a freshly installed before_tool_call hook never fires. The gateway-side plugins tool reports Plugin "<id>" not found while the CLI says loaded.
  • openclaw plugins reload does not fix it, and repeated reloads can retire the plugin inventory (Plugin inventory has retired; begin a new plugin operation, upstream #144291), which also breaks the in-chat openclaw delegate tool.
  • Fix: install and enable, then restart the Gateway. Do not churn plugins reload.

readonly-guard plugin (local)

Local hook-only plugin that blocks read-only work from riding in on a mutation tool.

  • Path: ~/.openclaw/policies/readonly-guard (installed with plugins install --link; plugins.entries."readonly-guard".enabled: true; also listed under plugins.load.paths).
  • Hook: before_tool_call, matcher ["exec"], priority 60. Blocks a code-mode exec payload that calls read-only tools and no mutating tool.
  • Escape hatch: a readonly-guard: allow comment in the payload, for read-only code-mode logic that genuinely needs code mode (for example a loop).

Group bot answers everything and leaks its reasoning (WhatsApp "Phamily", 2026-10-12)

Symptom: the family-planner agent replied to every message in the family group, and some replies were its own internal notes ("Holding silent on this one...", "Logged it to PLAN.md").

Root causes:

  • channels.whatsapp.groups["<jid>"].requireMention: false made every group message start a turn. The AGENTS.md rule "only speak when tagged" is advisory; the model broke it repeatedly.
  • With messages.groupChat.visibleReplies: "message_tool" the only public output is the message tool, but the end-of-turn nudge to "deliver a visible reply" made the model send its private final summary through message.

Fix (deterministic gate, applied with openclaw config set --batch-file, hot-reloaded, no restart):

  • channels.whatsapp.groups["120363412784470942@g.us"].requireMention = true (unmentioned messages become stored context only, no turn).
  • agents.entries.family-planner.groupChat.mentionPatterns = ["\\bmax\\b", "\\bfamily planner\\b"]. Agent-level list replaces the global one (Max, Family Planner, Planner), dropping the loose Planner word. Native @mention of the bot number and reply-to-bot still count as mentions.
  • Rewrote the "In the family WhatsApp group" section of the agent's AGENTS.md: the gate lives in config, at most one message per turn, never send reasoning/summary/"staying quiet" notes, do bookkeeping silently, end private with a one-liner.
  • Config backup: ~/.openclaw/openclaw.json.bak-pre-fp-gate-20261012.

Caveats: \bmax\b is case-insensitive, so the lowercase word "max" in normal chat also triggers a turn. To revert to always-on, set requireMention: false (or /activation always in the group as owner).

Deleting a bot's WhatsApp messages (checked 2026-10-12)

OpenClaw 2026.10.1 cannot delete or read WhatsApp messages: both openclaw message delete and the message tool's delete action answer "Message action delete not supported for channel whatsapp" (read is also unsupported). The only route is manual: open the group in WhatsApp on the phone that holds the bot number (Google Voice +12408121148 for Max), long-press the message, Delete, Delete for everyone (works for about 2 days after sending). Message IDs and send times for the bot's posts are in /tmp/openclaw/openclaw-YYYY-MM-DD.log (grep Sent message); the JID is hashed there, so match by time. Session history (sessions_history with includeTools) shows each post's text and ID.