Claude Code PreToolUseフックで「continue」を指定してはいけない理由 — Zodスキーマ検証の裏側を解説
出典: Iori

Claude Code v2.1.158のPreToolUseフックで「continue」を返すとJSON検証エラーが発生し、最終的に出力が返らなくなる問題が報告されました。有効値は「approve」と「block」のみで、存在しない値を指定するとZodスキーマのunion検証に引っかかります。この事例から学ぶ、AIツールのカスタマイズにおける型安全性の重要性を解説します。
Claude Codeのフック機構で遭遇する典型的な落とし穴
Claude Codeは、開発者がツール実行前後の動作をカスタマイズできる強力なフック機構を提供しています。しかし、その柔軟性の裏には厳格な型チェックが存在し、これを理解していないと思わぬエラーに遭遇します。
今回取り上げるのは、PreToolUseフックで直感的に「素通りさせたい」という意図で `{"decision": "continue"}` を返したところ、JSON検証エラーが連続発生し、最終的にシステムが応答しなくなったという実例です。この問題は、AIツールの内部実装を理解する上で重要な教訓を含んでいます。
問題の本質:Zodスキーマによる厳格な型検証
何が起きたのか
Claude Code v2.1.158において、PreToolUseフックから `{"decision": "continue"}` を返すと以下の挙動が観察されました:
正しい仕様
PreToolUseフックの `decision` フィールドには、**2つの有効値しか存在しません**:
`"continue"` や `"allow"` といった値は、いくら直感的に思えても**存在しない値**であり、スキーマ検証で確実に弾かれます。
Zodスキーマとは何か
Zodは、TypeScriptで広く使われる実行時型検証ライブラリです。Claude Codeの内部では、ユーザーからの入力(この場合はフックの返り値)が正しい形式かどうかをZodスキーマで検証しています。
// 内部実装のイメージ
const PreToolUseResponseSchema = z.object({
decision: z.union([z.literal("approve"), z.literal("block")])
});このスキーマに合致しない値を渡すと、union検証が失敗し、エラーが返されます。
編集部の視点
他のAIコーディングツールとの比較
この問題は、Claude Code特有のものではなく、AIツールのカスタマイズ機構全般に共通する設計思想を反映しています。
**GitHub Copilot**や**Cursor**などの競合ツールでも、拡張機能やプラグインには厳密な型定義が存在します。ただし、これらのツールは多くの場合、TypeScriptの静的型チェックに依存しており、実行時エラーよりもビルド時エラーで問題を検出します。
一方、Claude Codeは**実行時に動的にフックを評価する設計**を採用しているため、Zodによる実行時検証が必須となっています。これは柔軟性と引き換えに、開発者がランタイムエラーに遭遇するリスクを高めています。
メリットと注意点の両面分析
**メリット:**
**注意点:**
適用範囲の考察
この知見が特に重要なのは、以下のようなケースです:
特に最後のケースは要注意です。LLMは「continue」のような自然な英単語を好んで生成するため、**LLMにフックコードを書かせる際は、必ず有効値をプロンプトで明示する**必要があります。
今日から試せるアクション
1. フック設定を見直す
既存のPreToolUseフックを確認し、`decision` フィールドが `"approve"` または `"block"` のみを返していることを検証してください。
// ❌ 間違った実装
function preToolUse(params) {
return { decision: "continue" }; // これはエラーになる
}
// ✅ 正しい実装
function preToolUse(params) {
return { decision: "approve" }; // ツール実行を許可
}2. エラーログを定期監視する
`Hook JSON output validation failed` というエラーが出ていないか、ログを定期的にチェックしましょう。このエラーが頻発している場合、フック設定に問題がある可能性が高いです。
3. ドキュメントを常に参照する習慣をつける
APIやフックの仕様は、直感や推測ではなく**公式ドキュメントに基づいて実装する**ことが重要です。Claude Codeの場合、フックの仕様は頻繁に更新されるため、バージョンアップ時には必ずリリースノートを確認してください。
特にZodスキーマのような型検証機構が導入されている場合、「たぶんこれで動くだろう」という実装は確実に失敗します。型定義を確認する習慣が、長期的には開発効率を大きく向上させます。
---
この情報は @Iori さんの投稿を参考にしています。
出典: Iori


