Claude Media
Claude Code modが動かないときの切り分け — 症状別の原因とデバッグログ

Claude Code modが動かないときの切り分け — 症状別の原因とデバッグログ

Claude Code modが何もしないとき、読み込めない・hookがスキップされる・ツール呼び出しが拒否される・描画されない・編集が消える、の5症状をメッセージ別に切り分ける手順です。

Claude Code modが動かないときは、まず「modそのものが読み込まれたか」を確かめます。modのモジュールやhookが失敗すると、Claude Codeはそれを飛ばしてセッションを続けるため、壊れたmodは「何もしないmod」に見えるからです。手がかりは、modの名前を含む1行のメッセージです。その行を読む場所と、メッセージごとの原因を症状別にまとめます。

症状とメッセージの逆引き

見えている症状から、探すメッセージと出る場所を引きます。右端の列は、原因を詳しく書いた節です。

見えている症状探すメッセージ出る場所詳細
mods activeに名前がない探すメッセージnot loaded:出る場所debugログ詳細症状1
組織のポリシーでmodが拒否される探すメッセージallowManagedModsOnly出る場所debugログ。ホットリロード中はtranscriptにも詳細症状1
特定のhookだけ動かない探すメッセージhook skipped:出る場所同じ種類の失敗はリロードまで1回だけ表示。全件はdebugログ詳細症状2
登録したコマンドが答えない探すメッセージno command.run hook answered it出る場所コマンド実行時の返答詳細症状2
組み込み以外のmodがすべて外れた探すメッセージmods that run in the hooks worker are off for this session出る場所すべての対話セッションのtranscript詳細症状2
ツール呼び出しが拒否される探すメッセージa hook changed this call's input出る場所拒否理由としてClaudeに伝わる詳細症状3
denyルールを越えようとして拒否される探すメッセージtried to lift a deny rule in your settings出る場所transcriptとdebugログ(claude -pはdebugログのみ)詳細症状3
ペインやバンドが空のまま探すメッセージui.render (Pane) refused:出る場所--plugin-dirならtranscript。debugログではa hook returned a tree that does not validate詳細症状4
トーストが見えない探すメッセージ$.ui.toastの行出る場所debugログ詳細症状4
直したのに変わらない探すメッセージreload failed, the previous version stays loaded:出る場所--plugin-dirで編集中のtranscript詳細症状5

最初の4手 — 読み込み状態を確かめる

原因を探す前に、次の4つを順に試すと、問題が「読み込み前」か「読み込み後」かが分かります。

手順

modが何もしないときの確認順

  1. 1

    validateでmodの中身を静的に見る

    シェルでclaude plugin validateにmodのディレクトリを渡します。イベント名の綴り間違い、manifestの不備、読めないモジュールを、セッションを開かずに拾えます。

  2. 2

    plugin testで環境側の遮断を見る

    mod本体のないディレクトリでclaude plugin testを実行します。mod自体が読み込める環境かどうかを、メッセージで判別できます。

  3. 3

    /pluginの「mods active」行を見る

    セッション内で/pluginを開くと、タブの下に1 mod active · first-modのような行が出ます。ここにmodの名前がなければ、読み込みの段階で止まっています。

  4. 4

    debugログに出して名前でgrepする

    --debug-fileでログを書き出し、modの名前で絞り込みます。transcriptに何も出ないときの最終手段です。

claude plugin validate ./first-mod
cd ~ && claude plugin test
claude --debug-file ./mod-debug.log --plugin-dir ./first-mod

claude plugin testの返すメッセージは、読み込める環境かどうかを次のように分けます。

メッセージに含まれる語意味
no hooks module to load意味modは読み込める。このディレクトリにテスト対象がなかっただけ
hooks modules are turned off here意味disableAllHooksか組織のポリシーが遮断している
the rollout switch served off意味Anthropic側でインストール済みmodが遠隔で止められている
the rollout switch was saved off by an earlier session意味以前のセッションが保存した値を使っている。claudeを一度起動して値を更新してから再実行する

組織がallowManagedModsOnlyを設定している場合、このコマンドは報告しません。その場合は、インストールしたmodが拒否されたとき別のメッセージで理由が出ます。

手元のclaudeで確かめた出力

空のCLAUDE_CONFIG_DIRでclaude --versionとclaude plugin validate --helpを実行すると、v2.1.296では次のとおりでした。ログインやモデル呼び出しは伴いません。

$ claude --version
2.1.296 (Claude Code)
 
$ claude plugin validate --help
Usage: claude plugin validate [options] <path>
 
Validate a plugin or marketplace manifest, or the skills, agents, and commands
in a directory
 
Options:
  -h, --help  Display help for command
  --json      Output the validation report as JSON (same exit codes)
  --strict    Treat warnings as errors (exit 1). Use in CI to fail on
              unrecognized fields, missing metadata, and other issues that the
              runtime tolerates.

--helpの説明文が挙げる検査対象は、manifest、skills、agents、commandsです。troubleshootページが書く「イベント名の綴り間違いや読めないモジュールを拾う」は、この説明文からは読み取れません。CIに組み込むなら--strictを付けると、実行時には許容される未認識フィールドも終了コード1で落とせます。modのhookまで検査対象に含まれるかは、手元のmodに綴り間違いを仕込んで試すのが確実です。

メッセージはどこに出るのか

modを名指しする1行は、セッションの種類によって出る場所が違います。ここを取り違えると「何も出ない」と誤解します。

セッションの種類メッセージの場所
--plugin-dirで起動した対話セッション、またはClaudeが書いたmodのホットリロードを有効にしたセッションメッセージの場所transcriptに薄い色で1行
マーケットプレイスから入れたmodを動かす対話セッションなど、上記以外メッセージの場所debugログのみ。claude --debugで起動して確かめる
--plugin-dir付きのclaude -pメッセージの場所テキスト出力形式ではstderr。他のmodによる拒否はdebugログのみ

マーケットプレイス経由のmodが動かないのにtranscriptが静かなのは、不具合ではなく仕様どおりです。最初から--debugを付けて起動し直すのが近道です。

症状1: modが読み込まれない

コマンドも描画も挙動の変化もなく、mods activeの行にも名前がない状態です。debugログには、hooks module、modの名前、not loaded:で始まる行が出ます。たとえば--plugin-dirで読んだmodならhooks module first-mod@inline not loaded: disableAllHooks in managed settingsの形です。コロンの後ろが理由です。

理由の書き出し原因
hooks modules are turned off for installed plugins in this process: the rollout switch served off原因Anthropicが遠隔でインストール済みmodを止めている
同 ...saved off by an earlier session原因以前のセッションの保存値を使っている。Claude Codeを起動し直して更新する
disableAllHooks in managed settings原因組織がインストール済みプラグインのhookを止めている
only managed plugins and built-in plugins run原因allowManagedHooksOnlyが有効、または管理設定以外のファイルでdisableAllHooksが有効
installed plugins that are not managed load no hooks module in this mode (--bare)原因--bareで起動している
another plugin of that name loads first原因同名のプラグインが2つあり、管理されているほう、または先に読まれたほうが使われる

この表に当たらない場合は、次の原因を上から確かめます。

  • バージョンが古い: ターミナルではv2.1.287以降、Desktopアプリではv2.1.286以降が必要です。claude --versionで確かめます。
  • validateは通るのにhooksの行が出ない: hooks/hooks.jsonにmodulesキーがないか、綴りが違います。"modules": ["./register.js"]を足します。
  • hooks module did not load:: モジュールの読み込みに失敗しています。トップレベルのコードが例外を投げた場合などで、理由にはファイルと行が出ます。示されたエラーを直します。
  • options do not fit plugin.json userConfig: オプションがuserConfigの検証に失敗しています。maxを超える数値や、必須項目の未入力が典型です。行の末尾にsettings.jsonのpluginConfigsのエントリ名が出るので、そこの値を直します。
  • 初めて開いたディレクトリで何も読まれない: trustプロンプトに答えていません。そのディレクトリでclaudeを対話起動して受け入れます。
  • インストール済みプラグインがすべて読まれない: --safe-modeで起動していないか確かめます。--safe-modeそのものの使い方はClaude Codeのsafe modeにまとめています。

組織管理の端末やTeam・Enterpriseプランでは、組み込みの保護機構がmodやその応答を拒否することもあります。メッセージにmods are limited to your organization's by policy (allowManagedModsOnly)が含まれていれば、管理者が組織のmodだけを許可しています。debugログのほか、ホットリロード中のセッションではtranscriptにも出ます。

症状2: hookがスキップされる、modが外される

modは読み込まれたのに、特定のhookが飛ばされる、あるいはmodごと外されるケースです。メッセージで原因が分かれます。

メッセージ起きていること対処
hook skipped:起きていることhookが例外を投げた、制限時間(1イベントあたり10秒、prompt.editのhookは50ミリ秒)を超えた、または戻り値の形が違った。例: first-mod: tool.call hook skipped: threw Error: boom対処全件はdebugログで読む。同じイベント・同じ種類の失敗は、再読み込みまで1回しか表示されない
no command.run hook answered it起きていることmodが登録したコマンドを実行したのに、答えるhookがなかった。例: first-mod registered /tally but no command.run hook answered it対処command.runのhookがない、フィルタが別のコマンドを指している、next(e)を返している、のどれかを確かめる
it crashed the hooks worker起きていることfirst-mod was unloaded: it crashed the hooks workerの形で、modが外された対処下の説明を参照
its session.start ran again in a fresh copy起きていることモジュールが再読み込みされ、session.startが新しいコピーで再実行された対処下の説明を参照
mods that run in the hooks worker are off for this session起きていることワーカーが3回止まっても1つのmodに絞れず、組み込み以外のすべてのmod(組織がインストールしたものも含む)を外した対処/reload-pluginsで読み込み直す

no command.run hook answered itには、もうひとつの原因があります。hookがスキップされている場合で、$.ui.openにfocus: falseを渡したときもここに入ります。hookが確かに書いてあるなら、command.runに言及するhook skippedの行を探してください。理由はそこに出ます。テストでコマンドを実行しても同じ理由で失敗するので、再現にも使えます。

インストール済みmodは1つのワーカースレッドを共有しています。ワーカーが応答しなくなったり落ちたりして、原因がこのmodと突き止められると外されます。awaitのないループでスレッドを塞ぐhookが、原因のひとつです。

session.startの再実行は、ワーカーの入れ替えなどで起きます。$.prompt.submit・$.command.run・$.agent.spawnの呼び出しは最初の結果を返すだけで再実行されないため、直すことはありません。v2.1.292より前は、この呼び出しが2回実行され、プロンプトの送信やサブエージェントの起動が重複していました。

症状3: ツール呼び出しが拒否される

modもhookも動いているのに、modが触れたツール呼び出しが拒否されるケースです。拒否の理由として、次の2系統があります。

auto modeの「a hook changed this call's input」

auto modeでは、サーバー側の分類器が審査したあとにhookが呼び出しの入力を書き換えると、審査が実際に実行される内容をカバーしなくなるため拒否されます。書き換えたのはmodのtool.call・turn.stephookでも、settingsのPreToolUsehookでもありえて、メッセージはどれかを示しません。Claudeには「記録されたとおりにもう一度呼び出す」よう伝わります。それでも拒否されるなら、hookが毎回入力を書き換えています。modかhookを止めるか、auto modeを離れて自分で承認します。審査の仕組みはauto modeのサーバー側審査で扱っています。

設定のdenyルールに関するメッセージ

tried to lift a deny rule in your settingsは、modのtool.checkhookが、denyルールで拒否される呼び出しを承認しようとした場合に出ます。呼び出しは拒否されたままです。transcriptとdebugログにmodごと1セッション1回出ますが、claude -pではdebugログのみです。tool.checkで読めるフィールドはmodのtool.check解説にあります。

もう一つのthe deny rules in your settings could not be checked for this call, so it is refusedは、modが承認した呼び出しの検査自体が失敗したため拒否した、というメッセージです。こちらは拒否された呼び出しについてClaudeが読む理由に入ります。

どちらも、modがdenyを越えられない設計の結果です。対処はmodのhookを直すか、必要ならdenyルールの側を管理者と見直すことになります。

症状4: 描画が出ない、反応しない

ペイン、バンド、トースト、キー操作のいずれかが期待どおりに動かないケースです。

  • ペインやバンドが空、またはClaude Code標準の表示のまま: hookが返したツリーの検証が通っていません。--plugin-dirならtranscriptにui.render (Pane) refused:と理由が出ます。debugログにはa hook returned a tree that does not validateが出ます。要素が受け付けないpropや、アプリに存在しない要素が典型です。
  • threw while drawn:: 返されたツリー、またはnextに渡したpropsを描く途中でエラーになっています。末尾のthe engine drew its ownは、その場所が標準表示にフォールバックしたという意味です。v2.1.289より前は、transcriptの行でこのエラーが起きるとセッションが終了していました。
  • the module failed without a message: Clientがthrow new Error()のようにメッセージのないエラーで失敗しています。Clientのコードでthrowを探してメッセージを付けます。Clientの失敗をhookで受けて描き直す方法はui.faultの解説にあります。
  • $.ui.openを呼んだのにペインが出ない: ユーザー操作に由来しない呼び出しで、しかも端末がそのペインの必要幅より狭いと表示されません。コマンドやボタンから開くか、戻り値のisPlacedを確かめます。
  • ホットキーが効かない: ペインにキーボードフォーカスがありません。Ctrl+Xに続けてTabを押すか、ペインをクリックします。コマンドから開くときはfocus: trueを付けます。
  • ターミナルでは動くのにDesktopアプリで描かれない: そのレンダリング箇所や要素がDesktopでは使えません。リファレンスのrender sitesとelementsの表で対応面を確かめます。

トーストが出ないとき

対話ターミナルで$.ui.toastを呼んでも見えないときは、まずdebugログで呼び出しの行を探します。$.ui.toast (first-mod): build finishedのように、modの名前とトーストの文言が出ているはずです。行がない場合は、$.ui.toast dropped: timeoutMs is a whole number of ms, 1 to 60000のような拒否理由の行を探します。行があるのに見えないときの原因は次のとおりです。

状況見分け方と対処
別のペインがトーストを保留している見分け方と対処holdToasts付きで開いたペインが表示中。閉じると解除され、自分のペインなら$.ui.openからholdToastsを外す
従来のレンダラーで、プロンプトの下に出ている見分け方と対処右上の箱ではなく、modの名前で始まる1行がプロンプト直下にある
従来のレンダラーで、新しいトーストに置き換えられた見分け方と対処古い側のログ行がgave way, cut short(表示中だった)かgave way, unseen(未表示だった)で終わる。1つのトーストにまとめる
フルスクリーンレンダリングで描画前に時間切れ見分け方と対処同時に描かれるのは3つまで。該当行がleft the stack, never drawnで終わる。まとめて1つにする

v2.1.290より前は、前回のトーストから2秒以内に出したトーストが捨てられていました。その場合のログはwithin 2000ms of the last; droppedでした。

症状5: 編集や値が消える

modは動いているのに、直したはずの変更や、保存したはずの値が見当たらないケースです。原因は3つに絞れます。

  1. 編集が反映されない: インストール済みのプラグインを編集しています。Claude Codeが動かすのは、インストール版のキャッシュです。claude --plugin-dir ./first-modで作業コピーを指して開発すると、保存のたびに再読み込みされます。
  2. モジュールの再読み込みで値が戻る: モジュールレベルの変数は再読み込みのたびに初期化されます。値は$.stateか$.storeに置きます。
  3. /clear・/resume・/branchのあとで値が戻る: どのコマンドも$.stateを既定値に戻し、session.startは再発火しません。保存した値の読み込みはclassic.SessionStarthookで行います。

--plugin-dirで編集しているときは、再読み込みのたびにmodの名前とhookの一覧がtranscriptに出ます。保存で壊れた場合はreload failed, the previous version stays loaded:に理由が続き、最後に動いた版が、次に/reload-pluginsなどでプラグインが再読み込みされるまで動き続けます。保存したのに変わらないときは、この行を探します。

debugログの読み方

debugログには、読み込んだ・拒否したモジュール、失敗したhook、拒否した結果の行が1つずつ残ります。transcriptが静かなときの最後の頼りです。

claude --debug-file ./mod-debug.log --plugin-dir ./first-mod
# 別の端末で
tail -f ./mod-debug.log | grep first-mod

読み込めたmodには、名前と処理するイベントを並べた行があります。--plugin-dirで読んだmodは名前の後ろに@inlineが付きます。

hooks module first-mod@inline loaded (worker, environment 2, tier user); events: session.start,tool.call,command.run,ui.render

events:の並びに、期待するhookのイベント名があるかを確かめます。自分の調査用の行を足すには、$.ui.log('message', { to: 'debug' })と第2引数を付けます。第2引数がないと、transcriptに薄い色の行が追加されます。

切り分けを早くする順序

メッセージが見つからないときは、読み込みの前後で2つに割ると速く進みます。mods activeの行に名前があるかが分かれ目です。

  • 名前がない: 症状1の表。debugログでnot loaded:を探す
  • 名前がある: hook skippedの行、refused:の行、threw while drawn:の行のどれかをdebugログから探す

modを作る側なら、セッションを開く前にclaude plugin validateとclaude plugin testを回せば、イベントの綴りやhookの例外はここで落とせます。modの作り方そのものはmodを80行で作る手順にあります。

まとめ

modが何もしないように見えるのは、失敗がセッションを止めずに1行のメッセージだけで流れるためです。読む場所はセッションの種類で変わり、マーケットプレイスで入れたmodは--debugで起動しないとログすら残りません。まずmods activeの行で読み込みの前後を分け、読み込み前ならrefusalの表、読み込み後ならhook skippedやrefused:の行を、modの名前でgrepして追うのが最短です。

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