services/openclaw/troubleshooting.md
Table of Contents
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.apiKeyvalidation in the captured model catalog. openclaw gateway stopmay refuse unless--forceis supplied; Doctor's repair flow handled the stop itself.
Skills skipped as "symlink prefix resolves outside the root ancestry"
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:
defaultwith 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, nocommandfield) 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,ghreads, read-onlysed). - 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_callhook never fires. The gateway-sidepluginstool reportsPlugin "<id>" not foundwhile the CLI says loaded. openclaw plugins reloaddoes 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-chatopenclawdelegate 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 withplugins install --link;plugins.entries."readonly-guard".enabled: true; also listed underplugins.load.paths). - Hook:
before_tool_call, matcher["exec"], priority 60. Blocks a code-modeexecpayload that calls read-only tools and no mutating tool. - Escape hatch: a
readonly-guard: allowcomment 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: falsemade 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 themessagetool, but the end-of-turn nudge to "deliver a visible reply" made the model send its private final summary throughmessage.
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 loosePlannerword. 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
messageper 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.