Claude Codeの--agentsが「Invalid --agents configuration」で止まる
claude --agentsに渡したJSONが不正だとexit code 1で終了します。検査の順序、ファイル渡しの条件、resumeや--safe-modeで検査が働かない場面を解説します。
claude --agents に渡した値が不正だと、Claude Codeはセッションを始めず、Error: Invalid --agents configuration: を出して終了コード1で止まります。2行目以降に何が書かれるかは、値がどの段階で落ちたかで変わります。
この挙動はv2.1.242で入りました。それ以前は、不正な値でもセッションはそのまま起動していました。
出力の形と、検査が走る順番
エラーは次の形で出ます。1行目は固定で、<what failed> の部分が失敗の中身です。
Error: Invalid --agents configuration:
<what failed>検査は決まった順で走り、最初に失敗した時点で止まります。2種類の問題が同居していると、先に当たった側を直すまで、後ろの問題は表示されません。
--agentsの値が通る3つの関門
- 1
JSONとして読めるか
値が
{で始まるのに構文エラーなら、JSONパーサーのメッセージを載せたinvalid JSON:の1行が出ます。ファイルで渡した場合は、ファイルの中身が対象です。 - 2
サブエージェントの定義として正しいか
JSONとして読めても、各エージェントの定義がCLI定義サブエージェントのスキーマに合わなければ、問題ごとに1行ずつ出ます。
- 3
名前が - で始まっていないか
エージェント名が
-で始まると、<name>: agent names must not start with '-'が出ます。
問題行が20行を超えるときは、先頭の20行だけが表示され、残りは …and N more にまとまります。大きな定義ファイルを一気に書くと、全部直したつもりでも次の起動で別の行が出ることがあります。
原因の切り分け
メッセージの2行目を見れば、どの関門で落ちたかが分かります。
| 2行目の手がかり | 落ちた関門 | 見る場所 |
|---|---|---|
invalid JSON: で始まる | 落ちた関門1. JSON構文 | 見る場所末尾のカンマ、引用符、シェルによる引用符の欠落 |
| 問題ごとに複数行 | 落ちた関門2. スキーマ | 見る場所フィールド名と値の型 |
agent names must not start with '-' | 落ちた関門3. 名前 | 見る場所トップレベルのキー |
構文エラーの大半は引用符で起きる
JSONの文字列には二重引用符を使います。bashやzshでは全体を単一引用符で囲むのが基本で、公式のサンプルもそうなっています。
claude --agents '{
"reviewer": {
"description": "Reviews code changes",
"prompt": "You are a careful code reviewer."
}
}'PowerShellでは、ヒアドキュメント形式の @' ... '@ で囲みます。公式のWindows向け例も、この形を使っています。
claude --agents @'
{
"reviewer": {
"description": "Reviews code changes",
"prompt": "You are a careful code reviewer."
}
}
'@{ で始まらず、JSONとしても読めない値は、ファイルパスとして扱われます。シェルが引用符を食ってしまった結果、先頭が { でなくなると、構文エラーではなく別のエラーになります。これは次の節で扱います。
スキーマ違反は、フィールド名と値を表と突き合わせる
各エージェントの定義で使えるのは、prompt と、サブエージェントのfrontmatterと同じフィールドです。フィールド名はcamelCaseで書きます。型や許容値を間違えやすいものは次のとおりです。
| フィールド | 書ける値 |
|---|---|
model | 書ける値sonnet、opus、haiku、fable、claude-opus-5-5 のような完全なモデルID、または inherit |
permissionMode | 書ける値default、acceptEdits、auto、dontAsk、bypassPermissions、plan。manual は default の別名 |
effort | 書ける値low、medium、high、xhigh、max。使える段階はモデルで変わる |
memory | 書ける値user、project、local |
isolation | 書ける値worktree |
background / omitClaudeMd | 書ける値true |
tools / disallowedTools | 書ける値ツール名のカンマ区切り文字列、またはYAMLのリスト |
残りのフィールドは description、mcpServers、hooks、maxTurns、skills、initialPrompt です。
permissionMode のように許容値が決まっているフィールドに表にない値を書くと、2つ目の関門で弾かれます。直した例は次のとおりです。
{
"reviewer": {
"description": "Reviews code changes",
"prompt": "You are a careful code reviewer.",
"permissionMode": "acceptEdits"
}
}一方、フィールド名のほうは事情が違います。color と experimental は受け付けられず、エラーにはならずに無視されます。
複数の語からなるフィールド名(maxTurns や disallowedTools)はcamelCaseで、表の綴りと完全に一致させます。認識できないフィールドはエラーを出さずに無視されるので、max_turns や maxturns と書いた定義も Invalid は出ずに通り、上限だけが効きません。エラーが出ないのに効かないフィールドがあるときは、まずキーの綴りを表と1文字ずつ見比べます。そのうえで、綴りが合っていても効かない場合は、この記事の「検査を通ったのに設定が効かないとき」の条件に当てはまっていないかを確かめます。直前まで動いていた定義がある場合は、その差分から追うと原因を絞りやすくなります。
ファイルで渡すときの条件
定義が長くなったら、JSONファイルに切り出せます。ただし条件が2つあります。
--print(-p)と一緒に使うこと。対話セッションでファイルパスを渡すと拒否されます- Claude Code v2.1.281以降であること。それ以前は、ファイルパスもインラインJSONの一部として読まれ、JSONエラーになりました
claude -p --agents ./agents.json "Review my changes"ファイル渡しには、上のメッセージとは別の拒否文言があります。
| メッセージ | 意味 | 対処 |
|---|---|---|
Error: --agents takes a JSON object, or a file path only with --print (-p) | 意味対話セッションでパスを渡した | 対処インラインJSONにするか、-p を足す |
Error: --agents file not found: <path> | 意味そのパスにファイルがない | 対処パスか引用符を確認する |
2つ目は、引用符の取り違えでも出ます。先頭が { でない値、かつJSONとして読めない値は、パスと見なされるからです。
エラーの文面だけで原因を決めずに、シェルが実際に何を渡したかを先に確かめるのが近道です。
# 渡す前にJSONとして読めるか確かめる
jq . agents.jsonjq がエラーを返すなら、問題は1つ目の関門にあります。jq を通るのにClaude Codeが拒否するなら、2つ目か3つ目の関門です。
検査が働かない場面
Invalid が出ないから正しい、とは限りません。次の場面では検査自体が行われないか、行われ方が違います。
検査が働かない・変わる場面
--safe-mode / CLAUDE_CODE_SAFE_MODE
--agentsそのものが無視されます。値が不正でも、正しくても、定義は読み込まれません。safe modeはカスタムエージェントを含むカスタマイズを全部止める起動方法なので、切り分けの途中で使うと、--agentsが効いていないことに気づきにくくなります。--resume / --continue のインラインJSON
インラインのJSONは検査されず、セッションは始まります。壊れた値を渡しても、エラーなしで再開できます。
--resume / --continue のファイル渡し
ファイルから読んだ値は、起動のたびに検査されます。同じ
--agentsでも、インラインとファイルで再開時の挙動が分かれます。
再開時にインラインJSONが素通りする点は、スクリプトに組み込むときの落とし穴になります。新規起動では必ず落ちる値でも、--resume を付けた起動ではエラーが出ないので、テストが再開側だけで走っていると壊れた定義に気づけません。定義を検証したいときは、新規起動で確かめます。
検査を通ったのに設定が効かないとき
Invalid が出ずにセッションが始まっても、書いた値がそのまま効くとは限りません。公式のフィールド説明には、効き方を狭める条件がいくつかあります。
effortは、セッションの努力レベルを上書きしますが、環境変数CLAUDE_CODE_EFFORT_LEVELには勝てませんpermissionMode、mcpServers、hooks、initialPromptは、プラグインのサブエージェントでは無視されますomitClaudeMdは、そのエージェントがメインセッションとして動くときは無視されますpromptを空にしてmemoryも書かないエージェントを--agentで選ぶと、システムプロンプトは変わりません
どれも検査の対象外なので、エラーの有無だけでは見分けられません。
バージョンで変わる挙動
--agents まわりは、リリースごとに受け付ける範囲が広がってきました。古いClaude Codeでは、同じ値が別の結果になります。
| バージョン | 変わったこと |
|---|---|
| v2.1.242 | 変わったこと不正な値で終了コード1になる検査が入った。それ以前は不正でも起動した |
| v2.1.271 | 変わったこと定義に omitClaudeMd を書けるようになった |
| v2.1.281 | 変わったこと-p と組み合わせたファイル渡しに対応。prompt を空にすることもできるようになった |
チームで古いバージョンと新しいバージョンが混在していると、同じagents.jsonが片方では通り、もう片方ではInvalidになる、という状況が起きえます。
同名の定義との優先順位
--agents で渡した定義は現在のセッションだけに効き、ディスクには保存されません。同じ名前のサブエージェントが複数の場所にあるときは、managed settings、--agents、プロジェクトの.claude/agents/、ユーザーの~/.claude/agents/、プラグインの順で、前にあるものが使われます。
試しに既存と同名のエージェントを--agentsで渡して挙動を変えるときは、managed settingsで同名の定義が配られていないかを先に確かめる必要があります。managed settingsは組織が配布する設定で、同名の定義があるとそちらが優先され、--agents の定義は使われません。配布の有無は、組織の管理者に聞くのが確実です。
スクリプトに組み込むときの事前チェック
CIや自作ラッパーで --agents を使うなら、起動前にJSONの構文だけでも確かめておくと、失敗の原因をClaude Codeの終了コードから推測せずに済みます。
#!/usr/bin/env bash
set -euo pipefail
jq -e . agents.json > /dev/null # 構文エラーならここで止まる
claude -p --agents ./agents.json "Review my changes"jq が確かめるのは構文だけです。スキーマの検査は、Claude Code側の2つ目の関門が行います。
直す手順
- 2行目を見て、どの関門で落ちたかを判断する
- JSONなら
jq .で構文を確かめる - スキーマなら、フィールド名と値を上の表と突き合わせる
- 1つ直したら、もう一度起動する。後ろの関門の問題は、この時点で初めて表示される
- 20行を超える表示は先頭だけなので、全部直してからも再確認する
CLAUDE.mdを渡さないサブエージェントを --agents で定義するときの omitClaudeMd については、omitClaudeMdの解説にまとめています。ファイルベースの定義との使い分けは、サブエージェントの総合ガイドが扱っています。
よくある質問
toolsに存在しない名前を書くとどうなりますか
tools のどの項目もツールとして解決できないと、サブエージェントは多くの場合、起動に失敗します。その場合のエラーには、解決できなかった項目の名前が載ります。これは Invalid --agents configuration とは別のエラーで、定義が検査を通ったあとの実行時に出ます。
ビルトインのExploreとPlanを止めたいだけなら
--agents ではなく、環境変数で止める方法があります。手順はCLAUDE_CODE_DISABLE_EXPLORE_PLAN_AGENTSの記事にあります。