Claude Media
「spawned with zero tools」の対処 — Claude Codeのサブエージェント権限設定

「spawned with zero tools」の対処 — Claude Codeのサブエージェント権限設定

「Agent would be spawned with zero tools」でサブエージェントが起動しないときの3つの原因分類と直し方。tools/disallowedToolsの書き方、depth limitとの絡みまでまとめます。

Agent 'code-reviewer' would be spawned with zero tools — refusing. — サブエージェントの起動時にこう出たら、toolsリストの項目が1つも実際のツールに解決できなかったことを意味します。Claude Codeが起動そのものを拒否した状態です。ツールが0個のまま起動しても何もできないため、v2.1.208以降はこの時点で止める設計になりました。原因はエラーメッセージが挙げる3グループのどれかです。

エラーメッセージのどこを見るか

サブエージェント定義のtoolsフロントマターは、そのサブエージェントが使えるツールのallowlist(許可リスト)です。ここに書いた項目が実行時に1つも有効なツールへ解決できないと、Claude Codeは空のツールセットでの起動を拒否します。エラーには、解決できなかった項目名が挙がります。

v2.1.208より前は、ツールが0個のまま起動し、空の、または要領を得ない結果を返すという形で失敗していました。

Agent 'code-reviewer' would be spawned with zero tools — refusing. Its tools list resolved to nothing: unrecognized [Grpe]. Fix the agent's tools frontmatter or pass a different subagent_type.

unrecognizedの後ろの角括弧に、解決できなかった項目名が入ります。この例はGrepのつもりで書いたGrpeが1件だけ残った形で、この1件を直せば解決します。解決できなかった項目は、次の3グループに分類されます。

原因

解決できない項目の3グループ

  • 未認識(unrecognized)

    ツール名として存在しない文字列です。GrepをGrpeと書いた類のタイプミスが典型です。

  • サブエージェント非対応

    実在するツールですが、サブエージェントからは使えません。バックグラウンド実行では絞り込みで消える組み込みツールを書いたときが典型です。

  • このセッションに無い

    名前は正しいものの、今のセッションに該当ツールがありません。未接続のMCPサーバーを指すmcp__github__*や、深さの上限に達したサブエージェントのAgentが該当します。

拒否されるのは、toolsの全項目がこのどれかに落ちたときだけです。タイプミスが1つ混じっていても、他の項目が解決できていれば、残りのツールで起動します。

タイプミスはclaude plugin validateをすり抜ける

起動前に定義ファイルを検査したくなりますが、v2.1.287のclaude plugin validateはtoolsに書いたツール名の実在までは見ません。次の定義ファイルを一時ディレクトリに置いて実行した結果です。

---
name: code-reviewer
description: Reviews code changes
tools: Read, Grpe, LSP, mcp__github__*
---
Review the diff.
claude plugin validate .claude/agents
Validating components in: .../.claude/agents
 
✔ Validation passed

Grpeを含んでいても検査は通りました。このコマンドが拾うのはフロントマターのYAMLが読めないファイルで、対象は.claude/agentsのようなディレクトリで、指定して渡します(v2.1.233以降)。フロントマターが読めてもnameが無いファイルは、指摘の対象になりません。ツール名の誤りは、実際にサブエージェントを起動して初めて分かります。

定義ファイルそのものが読み込まれない場合は、「zero tools」とは別の問題です。プロジェクトやユーザーのagentsディレクトリでは、次のどれかに当たると、Claude Codeはそのファイルをセッションに通知せず飛ばします。

  • nameが無い(同じ場所に置いた説明文書として扱われる)
  • 先頭行が---で始まらない(フロントマター無しの文書として扱われる)
  • nameが-で始まる、または:を含む(デバッグログにエラーが出る)
  • descriptionが無い(理由はデバッグログに書かれる)
  • YAMLが読めない(デバッグログに構文エラーが出る)

飛ばされた理由を見るには、claude --debugで起動してデバッグログを確認します。disallowedToolsやmaxTurnsのようなキャメルケースの項目名は、綴りが違うと無視され、エラーも出ません。

バックグラウンドで消えるツール

一番気づきにくいのは、サブエージェントの実行形態でtoolsの解決結果が変わる点です。同じ定義でも、フォアグラウンドなら解決でき、バックグラウンドでは解決できない組み込みツールがあります。

くらべる

実行形態による組み込みツールの違い

ツールが多い

フォアグラウンド

メインの会話のツールを継承します。全サブエージェントに共通で除かれるツールだけが外れます。

ツールが少ない

バックグラウンド

組み込みツールは下の一覧に限られ、一覧外のツールはtoolsに書いても継承していても除かれます。MCPツールはすべて残ります。

バックグラウンドのサブエージェントが保持する組み込みツールは、次のとおりです。AgentとExitPlanModeは、実行形態ではなく別の条件で出し入れされます。SubagentHandbackで結果を報告するサブエージェントだけは、これに加えてSubagentHandbackも保持します。

Read / Grep / Glob / LSP / Bash / PowerShell
Edit / Write / NotebookEdit / WebFetch / WebSearch
TodoWrite / Skill / ToolSearch / EnterWorktree / ExitWorktree
Monitor / TaskStop / SendMessage / Artifact

LSPは一覧に入っています。v2.1.280より前はバックグラウンドで使えませんでしたが、今はこの一覧に含まれます。公式のエラー解説は、一覧から漏れるツールの例にCronCreateを挙げています。

除去そのものはエラーになりません。リストが空になったときにだけ、このエラーが出ます。

これとは別に、実行形態を問わず全サブエージェントから外れるツールもあります。

  • AskUserQuestion
  • EndConversation
  • EnterPlanMode
  • ScheduleWakeup
  • WaitForMcpServers
  • Workflow
  • ExitPlanMode(permissionModeがplanのときは残ります)

toolsにこれらしか書いていなければ、フォアグラウンドで動かしても解決先が残りません。

フォアグラウンドに寄せる方法

フォアグラウンドで動かせば、バックグラウンド向けの絞り込みの対象から外れます。ただし、background: trueを外すだけでは足りません。

インタラクティブなセッションでは、フォーク機能が既定でオンです。オンの間、Claudeが起動するサブエージェントはバックグラウンドで動きます。agent teamのチームメイトとして起動した場合のようにフォアグラウンドに留まる例外はありますが、Claudeの側からフォアグラウンドを頼む手段はありません。フォークを切るには環境変数CLAUDE_CODE_FORK_SUBAGENTを0にします。切ったあとで、Claudeにフォアグラウンドでの実行を頼めます。CLAUDE_CODE_DISABLE_BACKGROUND_TASKSを1にする手もあり、こちらは全サブエージェントがフォアグラウンドになります。

フォーク機能の既定がオンになったのはv2.1.232からです。非対話の-p実行とAgent SDKでは、既定はオフで、バックグラウンドが既定の動作になります。

フォークで起動したサブエージェント自体は、2つの絞り込みを受けません。メインの会話と同じツール群をそのまま受け取ります。仕組みの全体像はサブエージェントの解説にあります。

症状から直す手順

手順

エラーの項目別の直し方

  1. 1

    未認識の項目を直す

    エラーがunrecognizedに挙げた名前を、サブエージェントが使えるツールの名前と突き合わせて直します。まずタイプミスを疑ってください。

  2. 2

    非対応の項目は外すか、実行形態を変える

    そのツールをtoolsから外します。ツールが必要なら、前節の方法でフォアグラウンドに寄せます。

  3. 3

    セッションに無い項目はMCPと深さを見る

    MCPサーバーが未接続なら先に接続します。Agentが挙がっているなら、後述の深さの上限(depth limit)を見直します。

  4. 4

    絞る必要が無ければ`tools`ごと消す

    特定のツールに限定する理由が無いなら、toolsフィールドを省略します。省略すると、使えるツールをすべて継承します。

読み取り中心のレビュー役なら、動作が分かっているツール名だけで組み直せます。

tools: Read, Grep, Glob, Bash

tools: Agentだけがゼロになるケース

3番目のグループには、入れ子に関する特殊なパターンがあります。サブエージェントは既定で、メインの会話から数えて3階層下まで自分のサブエージェントを起動できます。この上限(depth limit)に達すると、Claude Codeはフォーク以外のすべてのサブエージェントからAgentツールを取り上げます。

toolsにAgentしか書いていないサブエージェントが深い階層で起動されると、ツールがゼロになってこのエラーになります。直し方は2つあります。

  • CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTHで上限を引き上げる
  • そのサブエージェントのtoolsにAgent以外のツールを最低1つ加える

前者は、その設定を読み込むすべてのサブエージェントに効きます。1つの定義だけを直したいなら、toolsを見直すほうが副作用は小さくなります。複数のサブエージェントが同じ深さで同じ理由に当たっているなら、上限の引き上げのほうが1か所で済みます。

逆に、レビュー役のように入れ子にしたくないサブエージェントは、toolsからAgentを省くかdisallowedToolsにAgentを書けば、それ以上は起動しません。

export CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=5

値は「メインの会話の下に何階層まで許すか」を表す正の整数で、数字以外を入れると無視されます。1にすると入れ子そのものが止まります。この変数はv2.1.217以降で使え、既定値はv2.1.217と2.1.218が1、v2.1.219以降が3です。v2.1.217〜2.1.218では既定が1のため、深さ1の時点で同じエラーに当たりやすくなります。

空リストと省略は別扱い

toolsを省略した場合は、このエラーは起きません。使えるツールをすべて継承する意味になるためです。

toolsを明示的に空にした場合や、disallowedToolsがtoolsの全項目を除いた場合も、拒否は発動しません。ツール無しでそのまま起動します。拒否が発動するのは、書いた項目がツールを指すつもりで、実際には1つも解決できなかったときだけです。

disallowedToolsはtoolsより先に適用されます。両方に同じ名前があれば、そのツールは除かれます。Bash(git push *)のように指定子を付けても、除かれるのはBashというツール全体です。そのため、次の組み合わせはtoolsが空になり、拒否ではなくツール無しの起動になります。

tools: Bash
disallowedTools: Bash(git push *)

git pushだけを止めたいときは、disallowedToolsではなくpermissions.denyにBashの拒否ルールを書きます。このルールはメインの会話にもサブエージェントにも効きます。

mcp__<server>とmcp__<server>__*は、サーバー単位でツールをまとめて指す書き方です。disallowedToolsではmcp__*で全サーバーのMCPツールを除けます。

サブエージェントがAPIエラーで途中停止する別のケースは、「Agent terminated early」の対処にあります。

まとめ

「zero tools」は、toolsに書いた全項目が解決できなかったときだけ出るエラーです。エラーに並ぶ項目名とグループが、そのまま直す場所を指します。

バックグラウンド実行が既定のいま、フォアグラウンドで動いていた定義が突然落ちたなら、まずtoolsの中身が絞り込みの一覧に入っているかを見てください。

この記事を共有:XはてブLinkedIn