claw-doctor
Diagnose and fix common OpenClaw / NanoClaw issues — broken skills, missing scripts, API key failures, path resolution bugs, and configuration problems. The meta-skill for when your claw is broken.
git clone https://github.com/tianyilt/openclaw-repair-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/tianyilt/openclaw-repair-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/claw-doctor" ~/.claude/skills/tianyilt-openclaw-repair-skills-claw-doctor && rm -rf "$T"
T=$(mktemp -d) && git clone --depth=1 https://github.com/tianyilt/openclaw-repair-skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/claw-doctor" ~/.openclaw/skills/tianyilt-openclaw-repair-skills-claw-doctor && rm -rf "$T"
skills/claw-doctor/SKILL.mdClaw Doctor — OpenClaw Self-Repair Skill
This skill diagnoses and fixes common OpenClaw / NanoClaw problems. When something breaks, run through the checklist below before giving up.
When to Activate
Activate this skill when the user reports any of the following:
- "skill not found" / skill does not trigger
- "No such file or directory" when running a skill script
- API key errors from a skill
- Skill produces no output or wrong output
- "SKILL.md is invalid" / YAML parse errors
- A skill works globally but not in workspace (or vice versa)
- Skills were working before but stopped after an update
Skill Load Order & Paths
OpenClaw loads skills from two locations. Workspace skills take priority.
Priority 1 (high): <workspace>/skills/<skill-name>/SKILL.md Priority 2 (low): ~/.openclaw/skills/<skill-name>/SKILL.md
Diagnostic: list all loaded skills
# Show what's installed globally ls ~/.openclaw/skills/ 2>/dev/null || echo "No global skills dir" # Show what's installed in current workspace ls ./skills/ 2>/dev/null || echo "No workspace skills dir"
If a skill appears in both, the workspace version wins — check for version mismatches.
Problem 1 — Skill Does Not Trigger
Symptom: User invokes a skill but Claude ignores it or does not follow the skill procedure.
Diagnosis checklist:
-
Is the
actually present and readable?SKILL.mdcat ./skills/<skill-name>/SKILL.md | head -20 -
Does the frontmatter YAML parse correctly?
python3 -c " import re, sys txt = open('skills/<skill-name>/SKILL.md').read() fm = re.search(r'^---\n(.*?)\n---', txt, re.DOTALL) print('Frontmatter found:', bool(fm)) if fm: import yaml; d = yaml.safe_load(fm.group(1)); print('Keys:', list(d.keys())) " -
Do the
in the SKILL.md match what the user said?keywords- Add more keyword variants (synonyms, abbreviations) if not matching.
-
Is
clear enough for the model to identify the skill?description- Short, specific descriptions outperform vague ones.
Fix: Ensure frontmatter is valid YAML (no tabs, proper quoting, correct indentation).
Problem 2 — Script Not Found (Path Resolution)
Symptom:
bash: scripts/run: No such file or directory
This is the most common skill bug. Scripts referenced in SKILL.md as
scripts/foo are relative to the skill's installation directory inside the OpenClaw plugin cache, not the current working directory.
Canonical fix — resolve the script path dynamically before every use:
# For a skill named "my-skill" with a script named "run" MY_SCRIPT=$(find ~/.openclaw -name "run" -path "*/my-skill/*/scripts/*" -type f 2>/dev/null | head -1) # Fallback: check workspace skills [ -z "$MY_SCRIPT" ] && MY_SCRIPT=$(find ./skills -name "run" -path "*/my-skill/scripts/*" -type f 2>/dev/null | head -1) if [ -z "$MY_SCRIPT" ]; then echo "ERROR: script not found. Is the skill installed?" exit 1 fi $MY_SCRIPT <args>
Also check: Is the script executable?
chmod +x ~/.openclaw/skills/my-skill/scripts/* chmod +x ./skills/my-skill/scripts/*
Problem 3 — API Key Not Configured
Symptom: Skill returns
{"success": false, "setup_required": true} or 401/403 errors.
Standard API key setup flow:
- The skill's SKILL.md should document where the key is stored (usually
or an env var).~/.openclaw/secrets/<skill-name>.key - Check if the key file exists:
ls ~/.openclaw/secrets/ 2>/dev/null || echo "No secrets dir" - Run the skill's setup command (usually
).scripts/run setup <api-key> - Verify the key was saved:
cat ~/.openclaw/secrets/<skill-name>.key 2>/dev/null | head -c 20
If no setup command exists, ask the user to set the env var directly:
export SKILL_API_KEY="their-key-here" # Add to ~/.zshrc or ~/.bashrc for persistence
Problem 4 — Dependency Missing (Node.js / Python / tool)
Symptom:
node: command not found, python3: No such file or directory, jq: command not found
Quick dependency check:
echo "=== Core deps ===" && \ node --version 2>/dev/null || echo "MISSING: node" && \ python3 --version 2>/dev/null || echo "MISSING: python3" && \ jq --version 2>/dev/null || echo "MISSING: jq" && \ curl --version 2>/dev/null | head -1 || echo "MISSING: curl"
Fix by platform:
| Tool | macOS | Ubuntu/Debian |
|---|---|---|
| Node.js | | |
| Python 3 | | |
| jq | | |
For Python skill dependencies:
pip3 install -r skills/<skill-name>/requirements.txt 2>/dev/null \ || echo "No requirements.txt found"
For Node skill dependencies:
cd skills/<skill-name> && npm install 2>/dev/null \ || echo "No package.json found"
Problem 5 — YAML Frontmatter Errors
Symptom: Skill loads but metadata is wrong / keywords not indexed.
Valid frontmatter template:
--- name: my-skill-name # lowercase, hyphens only description: One clear sentence describing what this skill does. keywords: - keyword-one - keyword-two license: MIT ---
Common mistakes:
| Mistake | Fix |
|---|---|
| Tabs instead of spaces | Replace with 2-space indentation |
Unquoted in description | Wrap value in quotes |
Missing field | Add it — it's required |
as inline list | Use block list |
Validate:
python3 -c " import yaml, sys txt = open('skills/<skill-name>/SKILL.md').read().split('---')[1] try: d = yaml.safe_load(txt) print('OK:', d) except yaml.YAMLError as e: print('YAML ERROR:', e) sys.exit(1) "
Problem 6 — Skill Worked Before, Broke After Update
Symptom: OpenClaw updated and a skill stopped working.
Checklist:
-
Check if the OpenClaw plugin cache was cleared:
ls ~/.openclaw/plugins/cache/ 2>/dev/null | head -10 -
Reinstall the skill from source:
# From a cloned skills repo cp -r /path/to/skills-repo/skills/<skill-name> ~/.openclaw/skills/ -
Check for breaking changes in OpenClaw's skill API — look at the OpenClaw changelog for
format updates.SKILL.md -
Test the script directly (bypassing OpenClaw):
bash skills/<skill-name>/scripts/<main-script> --help
Full Health Check
Run this to get a complete snapshot of the OpenClaw environment:
echo "=== OpenClaw Health Check ===" && \ echo "--- Global skills ---" && ls ~/.openclaw/skills/ 2>/dev/null || echo "(none)" && \ echo "--- Workspace skills ---" && ls ./skills/ 2>/dev/null || echo "(none)" && \ echo "--- Secrets ---" && ls ~/.openclaw/secrets/ 2>/dev/null || echo "(none)" && \ echo "--- Plugin cache ---" && ls ~/.openclaw/plugins/cache/ 2>/dev/null | head -5 || echo "(empty)" && \ echo "--- Dependencies ---" && \ node --version 2>/dev/null && \ python3 --version 2>/dev/null && \ jq --version 2>/dev/null && \ echo "=== Done ==="
For Claude Code Users
This skill also works as a Claude Code user-invocable skill. Add the following to
~/.claude/CLAUDE.md under ## User-Invocable Skills:
### claw-doctor Diagnose and fix OpenClaw / NanoClaw problems. **Trigger**: user mentions skill not loading, script not found, API key error, SKILL.md broken, OpenClaw not working **Procedure**: Follow the claw-doctor SKILL.md checklist: 1. Identify symptom category (trigger / script path / API key / dependency / YAML / post-update) 2. Run the relevant diagnostic commands 3. Apply the fix and verify with the Full Health Check
Problem 7 — 飞书 Bot 用了错误的模型
症状:飞书里回复的模型和
openclaw.json 配置的不一致,或 /new 之后还是老模型。
根因 1 — Session 里的 model override 覆盖了 agent 配置
Session 文件会持久化上一次手动切换的模型,重启后也不会清除。
# 找出哪个 session 有 model override python3 -c " import json for agent in ['main', 'sii']: path = f'/Users/tianyiliang/.openclaw/agents/{agent}/sessions/sessions.json' # 按实际路径调整 try: data = json.load(open(path)) for k, v in data.items(): if v.get('model'): print(f'[{agent}] {k}: model={v[\"model\"]}') except: pass "
修复:删掉对应 session 里的
model/modelProvider 字段,或直接删掉整个 session 条目,再重启 gateway:
openclaw gateway restart
根因 2 —
agent 不在 main
,binding 被忽略agents.list
bindings 里写了 "agentId": "main" 但不生效——因为 main 是内置 agent,不在 agents.list 里就不能作为路由目标。
诊断:
openclaw agents list --bindings # 看 main 是否出现
修复:把
main 显式加入 agents.list:
python3 -c " import json path = '~/.openclaw/openclaw.json' # 按实际路径 cfg = json.load(open(path)) if not any(a['id'] == 'main' for a in cfg['agents']['list']): cfg['agents']['list'].insert(0, { 'id': 'main', 'name': 'main', 'workspace': cfg['agents']['defaults']['workspace'], 'model': {'primary': 'custom-local/gemini-3-pro-preview', 'fallbacks': []} }) json.dump(cfg, open(path,'w'), indent=2, ensure_ascii=False) print('Added main to agents.list') "
根因 3 — Model ID 和本地代理不匹配导致 fallback
openclaw.json 里配的 model ID 在 localhost proxy 上不存在,静默 fallback 到下一个。
# 查实际可用的模型 curl -s http://localhost:8317/v1/models -H "Authorization: Bearer your-api-key-1" \ | python3 -c "import json,sys; [print(m['id']) for m in json.load(sys.stdin)['data']]" | sort
对比
openclaw.json 里的 model ID,确保完全匹配。
Problem 8 — Cron Jobs 走了 OpenRouter
症状:
openclaw status 里 cron session 显示 model=openrouter/auto,不应该走云端。
根因:session 里有
authProfileOverride: openrouter:* 被持久化(某次 auth 自动切换的残留)。
诊断:
python3 -c " import json for agent in ['main', 'sii']: path = f'~/.openclaw/agents/{agent}/sessions/sessions.json' try: data = json.load(open(path)) for k, v in data.items(): if 'cron' in k and 'openrouter' in v.get('authProfileOverride',''): print(f'[{agent}] {k}: auth={v[\"authProfileOverride\"]} model={v.get(\"model\")}') except: pass "
修复:清掉所有 cron session 里的 openrouter 覆盖:
python3 -c " import json, glob for path in glob.glob('~/.openclaw/agents/*/sessions/sessions.json'): data = json.load(open(path)) changed = False for k, v in data.items(): if 'cron' in k and 'openrouter' in v.get('authProfileOverride',''): for field in ['model','modelProvider','authProfileOverride','authProfileOverrideSource','authProfileOverrideCompactionCount']: v.pop(field, None) changed = True print(f'Fixed: {k}') if changed: json.dump(data, open(path,'w'), ensure_ascii=False) " && openclaw gateway restart
Problem 9 — Gateway 无反应 / device signature invalid
device signature invalid症状:
openclaw status 报 RPC probe: failed,错误为 gateway closed (1008): device signature invalid。飞书 bot 不回复,gateway 看起来在跑但 CLI 连不上。
根因:升级 openclaw 版本后,旧版 LaunchAgent(
com.clawdbot.gateway,加载 openclaw-cn)没有被清理,与新版 ai.openclaw.gateway 同时注册开机启动。旧进程先抢占 18789 端口,新版 CLI 因 device signature 格式不兼容被拒绝。
诊断:
launchctl list | grep -i claw # 如果同时出现 com.clawdbot.gateway 和 ai.openclaw.gateway,就是这个问题 openclaw gateway status 2>&1 | grep -E "RPC|device|pid"
修复:
# 1. 备份并禁用旧版 LaunchAgent cp ~/Library/LaunchAgents/com.clawdbot.gateway.plist \ ~/Library/LaunchAgents/com.clawdbot.gateway.plist.bak launchctl bootout gui/$UID/com.clawdbot.gateway mv ~/Library/LaunchAgents/com.clawdbot.gateway.plist \ ~/Library/LaunchAgents/com.clawdbot.gateway.plist.disabled # 2. 重启新版 gateway openclaw gateway restart # 验证 openclaw gateway status 2>&1 | grep "RPC probe" # 期望输出:RPC probe: ok
说明:
.plist.disabled 文件 launchd 开机不会加载(只识别 .plist 后缀),相当于禁用但保留备份。
Problem 10 — 非 Owner 用户被拦截(OAuth 授权 / 工具调用)
症状:非应用 Owner 的飞书用户发消息后,授权入口或工具调用被拒绝,日志中出现
OwnerAccessDeniedError 或 Permission denied: Only the app owner is authorized。
根因:
assertOwnerAccessStrict 默认 ownerOnly=true,所有非 Owner 用户全部拒绝。这是 openclaw-lark 上游的已知问题(issues #5、#12)。
修复方案 A — 配置关闭(推荐):在
openclaw.json 的飞书 channel 里加 uat.ownerOnly: false:
# 用 python3 安全写入,避免手编 JSON 出错 python3 - <<'EOF' import json path = '/Users/tianyiliang/.openclaw/openclaw.json' # 按实际路径调整 cfg = json.load(open(path)) ch = cfg.setdefault('channels', {}).setdefault('feishu', {}) uat = ch.setdefault('uat', {}) uat['enabled'] = True uat['ownerOnly'] = False json.dump(cfg, open(path, 'w'), indent=2, ensure_ascii=False) print('Done. Run: openclaw gateway restart') EOF
修复方案 B — 升级插件:如果你使用 workspace 源码版插件(
openclaw-lark),该 patch 已包含在 PR #11 中:
:src/core/config-schema.ts
加UATConfigSchemaownerOnly?: boolean
:src/core/owner-policy.ts
里检查assertOwnerAccessStrict
flagownerOnly
验证:重启 gateway 后,非 Owner 用户发消息,日志中不再出现
OwnerAccessDeniedError。
Contributing
Found a new OpenClaw failure mode? Open a PR with:
- The symptom (exact error message or behavior)
- Root cause
- Diagnostic command
- Fix
Keep entries short and command-first. The doctor should be fast to consult.