CLAUDE LABEN
TEACHERS — AnthropicがClaude for Teachersを公開。米国K-12の認証済み教員に、プレミアム機能と授業向けスキル、全50州の学習指導基準に沿ったカリキュラム連携を無償提供しますADMIN — Claude Enterprise全組織でAdmin APIがベータ提供に。メンバーと招待の操作はベータヘッダー不要、グループとカスタムロールは専用ヘッダーが必要ですM365 — Microsoft 365コネクタに書き込みツールが追加。メールの下書き・送信・整理、カレンダー操作、OneDriveとSharePointのファイル作成・更新まで任せられますMCP — --mcp-configや.mcp.jsonのサーバ単位request_timeout_msが無視され、新規セッションで60秒既定のままタイムアウトする不具合が修正されましたSUBAGENT — --forward-subagent-textとCLAUDE_CODE_FORWARD_SUBAGENT_TEXTが追加。サブエージェントのテキストと思考をstream-json出力に含められますDEADLINE — 7月24日にOpus 4.7のfastモードが削除されます。残り7日、speed: "fast" はエラーになるためOpus 4.8への移行をご確認くださいTEACHERS — AnthropicがClaude for Teachersを公開。米国K-12の認証済み教員に、プレミアム機能と授業向けスキル、全50州の学習指導基準に沿ったカリキュラム連携を無償提供しますADMIN — Claude Enterprise全組織でAdmin APIがベータ提供に。メンバーと招待の操作はベータヘッダー不要、グループとカスタムロールは専用ヘッダーが必要ですM365 — Microsoft 365コネクタに書き込みツールが追加。メールの下書き・送信・整理、カレンダー操作、OneDriveとSharePointのファイル作成・更新まで任せられますMCP — --mcp-configや.mcp.jsonのサーバ単位request_timeout_msが無視され、新規セッションで60秒既定のままタイムアウトする不具合が修正されましたSUBAGENT — --forward-subagent-textとCLAUDE_CODE_FORWARD_SUBAGENT_TEXTが追加。サブエージェントのテキストと思考をstream-json出力に含められますDEADLINE — 7月24日にOpus 4.7のfastモードが削除されます。残り7日、speed: "fast" はエラーになるためOpus 4.8への移行をご確認ください
記事一覧/Claude Code
Claude Code/2026-05-21中級

Claude Code Hook が `command timed out` で失敗するときの timeout 設定と分割実行のコツ

Claude Code の Hook が `command timed out` で発火しても完了しない問題を、timeout 設定の見直し・分割実行・バックグラウンド化の3アプローチで実用的に解決する手順をまとめます。

claude-code129hooks14troubleshooting61timeout8settings5

Claude Code に PostToolUse で eslint --fix を仕込んだ朝、ターミナルが赤いログで埋まりました。Hook 'lint-all' command timed out after 60s — フックは確かに発火しているのに、規模の大きい monorepo を相手にすると 60 秒で打ち切られてしまうのです。私自身、2014年からアプリ開発を続けるなかで、いつの間にか肥大化したフロントエンド側のリント設定がそのまま Claude Code の自動修正フローに足を引っ張る、というのは結構ありがちな場面でした。

このエラーは Hook の non-zero exit code とは別物で、コマンド自体は正しく動き始めているのに、Claude Code 側のウォッチドッグが上限秒数で SIGTERM を投げて停止させているために起こります。原因の切り分けと、ハマらない設定の組み立て方を順に書き出します。

command timed out が出る瞬間に何が起きているのか

Claude Code は Hook 実行時に、設定した(または既定の)秒数を超えるとプロセスツリーを SIGTERM で停止します。既定値はバージョンによって異なりますが、私の手元のクライアントでは 60 秒でした。フック側のコマンドは独立した子プロセスで起動するため、Claude Code 本体のセッションは生きていても、フックだけが「途中で死ぬ」状態になります。

ここで一番見落としやすいのは、Hook の中で & でバックグラウンド化していても、プロセスツリー全体が監視対象になっているという点です。npm run lint & のように書いても、シェルが終了するまでに lint が完了していなければ、結局子プロセスごと止められます。フック側で disown するか、後述のように完全に切り離す必要があります。

タイムアウトに引っかかるパターンの典型は、ESLint の全ファイル走査、Prettier の monorepo 全体実行、tsc --noEmit、Jest の全テスト、Docker イメージのビルドあたりです。どれも単体ではよく使うコマンドですが、Hook の文脈で毎回走らせる種類のものではありません。

まず疑うのは「フックの粒度」のほうで、timeout 設定ではない

時間が足りないとき、timeout を 60 → 300 秒に伸ばす対応をしがちですが、これは根本解決にはなりません。Hook はツール呼び出しのたびに走るので、たとえば 5 分の lint を入れると、ファイル 1 つ編集するたびに 5 分待たされる体験になります。Claude Code が補完してくれる速度を生かすには、Hook 自体が秒単位で終わる粒度に絞り込むのが先です。

実用的には、PostToolUse の matcher で対象を Edit / Write / NotebookEdit に絞ったうえで、Hook の中身も「直近に変更されたファイルだけを対象にする」スクリプトに置き換えます。tool_input.file_path を環境変数経由で受け取れる仕組みを利用して、ファイル単位の lint や prettier を回します。

#!/usr/bin/env bash
# .claude/hooks/post-edit-lint.sh
set -euo pipefail
 
# Claude Code が渡してくる JSON から file_path を取り出す
FILE="$(jq -r '.tool_input.file_path // empty' <<< "${CLAUDE_HOOK_INPUT:-}")"
[[ -z "$FILE" ]] && exit 0
[[ ! -f "$FILE" ]] && exit 0
 
# 拡張子で振り分けて、対象ファイルだけ処理する
case "$FILE" in
  *.ts|*.tsx|*.js|*.jsx)
    npx --no-install eslint --fix --max-warnings=0 "$FILE"
    ;;
  *.md|*.mdx|*.json|*.yaml|*.yml)
    npx --no-install prettier --write "$FILE"
    ;;
esac

このスクリプトなら、eslint . のようにプロジェクト全体を見にいく動きにはならず、編集された 1 ファイルだけが対象になります。私のアプリ開発のリポジトリでも、monorepo 全体だと 90 秒近くかかっていた lint が、ファイル単位なら 2〜3 秒で安定して終わります。

それでも長く走らせたいときの timeout 設定の書き方

「フックを軽くしても、どうしても 60 秒を超える処理を入れたい」場面はあります。たとえば PostToolUse でビルドスクリプトを動かしたい、Stop Hook で大きめのテストを走らせたい、といったケースです。Claude Code の settings.json では、各 Hook ごとに timeout を明示できます。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/post-edit-lint.sh",
            "timeout": 30
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/run-build.sh",
            "timeout": 300
          }
        ]
      }
    ]
  }
}

timeout の単位は秒です。ミリ秒で書きたくなる方を時々お見かけしますが、Claude Code の Hook 設定は秒単位で統一されています。500 を入れると 500 秒待つので注意してください。Stop Hook など、ユーザーが「終了」を意図したタイミングで走るフックは長めに取っても体感を損ねません。一方 PostToolUse のように頻繁に発火するフックは、長くても 30 秒程度に抑えるのが現実的です。

設定変更を反映させるには、Claude Code セッションを再起動する必要があります。Hot reload はされない仕様なので、/exit してから入り直すか、別の新しいセッションを開いてください。

バックグラウンドで完全に切り離してから「結果だけ拾う」パターン

Hook で長時間処理を回したいけれど、Claude Code の応答を待たせたくない場合は、フック側でジョブを完全にデタッチしてから別の場所で結果を確認するアプローチが効きます。nohupsetsid の組み合わせで親プロセスから切り離します。

#!/usr/bin/env bash
# .claude/hooks/post-edit-build.sh
set -euo pipefail
 
LOG_DIR="${HOME}/.claude/hook-logs"
mkdir -p "$LOG_DIR"
TS="$(date +%Y%m%d-%H%M%S)"
LOG="${LOG_DIR}/build-${TS}.log"
 
# Claude Code 側のフック監視対象から完全に切り離す
setsid nohup bash -c "
  cd \"$(pwd)\"
  npm run build > '$LOG' 2>&1
  echo \"exit=\$?\" >> '$LOG'
" </dev/null >/dev/null 2>&1 &
disown || true
 
# Hook 自身は即座に成功で返す
echo "build kicked off → $LOG"
exit 0

ポイントは setsid で新しいセッションを作り、nohup でハングアップ無視、そして disown でジョブテーブルから外していることです。これで Claude Code のフック監視は数十ミリ秒で完了し、ビルドは裏で続きます。結果はログファイルに残るので、AdMob 収益レポートの集計やデプロイ後の検証など、後追いで確認したい処理向きです。

ただしこの方式は「フックがビルド失敗を即時に知らせてくれない」というトレードオフを伴います。失敗を Claude Code に伝えたいなら、後段で Stop Hook かユーザー側のスクリプトでログをチェックして、エラーがあれば次のターンで Claude Code に共有する、という二段構えにします。

ハマったときに最初に見るログの場所

command timed out が出たかどうかは、Claude Code の標準出力にも記録されますが、流れて消えやすい情報です。Hook 自体の動きを別ログに残すようにしておくと、原因切り分けが速くなります。先ほどの post-edit-lint.sh の冒頭に次の数行を入れておくと、何が呼ばれたかを後から追えます。

# 冒頭のログ出力
LOG_DIR="${HOME}/.claude/hook-logs"
mkdir -p "$LOG_DIR"
exec > >(tee -a "$LOG_DIR/hook-$(date +%Y%m%d).log") 2>&1
echo "[$(date '+%H:%M:%S')] hook=post-edit-lint file=$FILE"

これだけで、Hook が呼ばれた瞬間のタイムスタンプと、Claude Code が渡してきた file_path が日次ログに溜まります。タイムアウトの直前で時間がかかっているコマンドが何なのか、set -x を一時的に有効にして洗い出すと原因が見えてきます。

私の手元では、SwiftLint を含む iOS 系のフックが一度 60 秒を越えていて、調べてみると xcodebuild -showBuildSettings を毎回呼んでいたのが原因でした。同じプロジェクトで同じ設定値を毎回問い合わせる必要はないので、初回だけ計算して /tmp にキャッシュする 5 行を追加するだけで 70 秒→3 秒に縮みました。タイムアウトの正体は「重い処理」ではなく、「重い処理を毎回回している設計」のほうにあることが多いです。

私が今使っている Hook 設定の指針

最後に、現時点で私が落ち着いた指針を 5 つだけ書き残します。

第一に、PostToolUse は 30 秒以内に終わるものだけ置く。それ以上かかるものは Stop Hook かバックグラウンドジョブに回します。第二に、フック内で必ず対象ファイルを絞る。tool_input.file_path を見て、対象拡張子でなければ即座に exit 0。第三に、npx --no-install を使って依存ダウンロードを抑える。Hook が初回だけ重くなる現象を避けられます。第四に、ログは必ず日次ファイルに分けて残す。原因切り分けの時間が一気に短くなります。第五に、ビルドや E2E テストのように本質的に長いものは Hook ではなくスケジュールタスクや CI に寄せる。Claude Code のセッションをブロックさせない設計を優先します。

Hook は便利な分、設計を間違えるとセッション全体の体感速度を一気に落とします。「気持ちよく速い Claude Code」を保つために、command timed out が出たら timeout を伸ばす前に粒度を見直す、というのが当面の私のルールです。同じところで時間を溶かしてしまった方の手がかりになれば幸いです。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Claude Code2026-06-18
壊れた settings.json で Claude Code が起動しなくなったとき — セーフモードの挙動と設定の分け方
settings.json の構文ミスで Claude Code が起動しなくなったときに、どの階層が壊れているかを切り分けて数分で復旧する手順と、自動運用で壊れにくい設定の分割・検証パターンをまとめました。
Claude Code2026-04-25
Claude Code Hooksが無限ループする問題 — PostToolUseが自己発火するときの止め方
Claude Code の Hooks を仕掛けたら、ツール呼び出しが止まらなくなった。PostToolUse が自分で書き換えたファイルを再び拾って延々と発火し続ける、典型的な無限ループの原因と止め方を実例ベースで解説します。
Claude Code2026-04-24
Claude Code エラー完全対処辞典 — 認証・決済・応答停止・ツール失敗を症状から逆引きする
Claude Code で実際に遭遇する 40 超のエラーパターンを、症状 → 原因 → 復旧手順の順で整理した実務向けハンドブックです。認証・決済・応答停止・ツール失敗・MCP・Hook まで、根本原因まで追える資料として活用いただけます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →