原文(日本語訳)
フックブロッキングエラー(終了コード2)が発生した際、標準エラー出力(stderr)がユーザーに表示されなかった問題を修正しました。
原文(英語)
Fixed hook blocking errors (exit code 2) not showing stderr to the user
概要
Claude Code 2.1.39では、設定されたフック(hooks)が終了コード2でブロッキングエラーを返した際、エラーの詳細情報(標準エラー出力)がユーザーに表示されず、問題の原因を特定できなかった問題が修正されました。修正後は、フックがブロックした理由が明確に表示されるようになり、デバッグが容易になりました。
フックとは
Claude Codeのフック(hooks)は、特定のイベント(ツール呼び出し、プロンプト送信など)に応じて自動実行されるシェルコマンドです。これにより、セキュリティチェック、ログ記録、承認フローなどを実装できます。
終了コードの意味
| 終了コード | 意味 | 動作 |
|---|---|---|
| 0 | 成功 | 処理を続行 |
| 1 | エラー | エラーを表示して続行 |
| 2 | ブロッキング | 処理を中止(ブロック) |
実践例
セキュリティチェックフックの例
bash
# ~/.claude/hooks/pre-bash.sh
#!/bin/bash
# 危険なコマンドをブロック
if echo "$CLAUDE_TOOL_COMMAND" | grep -qE "rm -rf|format|dd"; then
echo "Error: Dangerous command blocked!" >&2
echo "Attempted command: $CLAUDE_TOOL_COMMAND" >&2
echo "Reason: This command could cause data loss" >&2
exit 2 # ブロッキングエラー
fi
exit 0修正前の動作
bash
claude
# > "Delete all temporary files with rm -rf /tmp/*"
# ユーザーに表示される内容:
# Error: Hook blocked the operation (exit code 2)
# 何が問題なのか、なぜブロックされたのか不明修正後の動作
bash
claude
# > "Delete all temporary files with rm -rf /tmp/*"
# ユーザーに表示される内容:
# Error: Hook blocked the operation (exit code 2)
#
# Hook output (stderr):
# Error: Dangerous command blocked!
# Attempted command: rm -rf /tmp/*
# Reason: This command could cause data loss
# 問題の原因が明確に表示されるコード品質チェックフック
bash
# ~/.claude/hooks/pre-write.sh
#!/bin/bash
FILE_PATH="$CLAUDE_TOOL_FILE_PATH"
FILE_CONTENT="$CLAUDE_TOOL_CONTENT"
# TODOコメントの残留をチェック
if echo "$FILE_CONTENT" | grep -q "TODO\|FIXME\|HACK"; then
echo "Error: Code quality check failed" >&2
echo "File: $FILE_PATH" >&2
echo "Issue: Code contains TODO/FIXME/HACK comments" >&2
echo "Please resolve these before proceeding" >&2
exit 2
fi
exit 0修正後は、どのファイルのどの箇所が問題なのか、詳細が表示されます。
API使用制限チェック
bash
# ~/.claude/hooks/pre-prompt.sh
#!/bin/bash
# API使用量をチェック
USAGE=$(curl -s https://api.anthropic.com/usage)
LIMIT=1000000 # トークン上限
CURRENT=$(echo "$USAGE" | jq '.tokens_used')
if [ "$CURRENT" -gt "$LIMIT" ]; then
echo "Error: API usage limit exceeded" >&2
echo "Current usage: $CURRENT tokens" >&2
echo "Limit: $LIMIT tokens" >&2
echo "Please wait until the next billing cycle" >&2
exit 2
fi
exit 0コンプライアンスチェック
bash
# ~/.claude/hooks/pre-bash.sh
#!/bin/bash
# 本番環境での操作をブロック
if [ "$CLAUDE_PROJECT_ENV" = "production" ]; then
echo "Error: Production environment detected" >&2
echo "Direct modifications to production are not allowed" >&2
echo "Please use the staging environment and deployment pipeline" >&2
echo "" >&2
echo "To override (not recommended):" >&2
echo " export CLAUDE_ALLOW_PROD=1" >&2
exit 2
fi
exit 0フック設定ファイルの例
json
// ~/.claude/settings.json
{
"hooks": {
"pre-bash": "~/.claude/hooks/pre-bash.sh",
"pre-write": "~/.claude/hooks/pre-write.sh",
"pre-prompt": "~/.claude/hooks/pre-prompt.sh",
"post-response": "~/.claude/hooks/post-response.sh"
}
}デバッグのベストプラクティス
詳細なエラーメッセージの出力
bash
#!/bin/bash
# 良い例: 詳細な情報を stderr に出力
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >&2
echo "Hook: pre-bash" >&2
echo "Error: Command validation failed" >&2
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >&2
echo "Command: $CLAUDE_TOOL_COMMAND" >&2
echo "Reason: Contains dangerous pattern" >&2
echo "Suggestion: Use safer alternatives" >&2
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >&2
exit 2ログファイルへの記録
bash
#!/bin/bash
LOG_FILE="$HOME/.claude/logs/hooks.log"
TIMESTAMP=$(date -Iseconds)
# ログファイルに詳細を記録
{
echo "[$TIMESTAMP] Hook blocked operation"
echo " Command: $CLAUDE_TOOL_COMMAND"
echo " Reason: Security policy violation"
} >> "$LOG_FILE"
# ユーザーにも表示
echo "Error: Operation blocked by security policy" >&2
echo "Details logged to: $LOG_FILE" >&2
exit 2注意点
- stderrへの出力: エラー情報は必ず標準エラー出力(
>&2)に出力してください。標準出力に出力してもユーザーには表示されません - 終了コード: ブロックする場合は必ず終了コード2を使用してください
- パフォーマンス: フックは各操作で実行されるため、重い処理は避けてください
- デバッグモード:
CLAUDE_DEBUG=1環境変数を設定すると、フックの詳細なログが表示されます
トラブルシューティング
フックが正しく動作しない場合
bash
# フックスクリプトに実行権限を付与
chmod +x ~/.claude/hooks/*.sh
# フックのテスト実行
CLAUDE_TOOL_COMMAND="test" ~/.claude/hooks/pre-bash.sh
echo "Exit code: $?"デバッグモードの有効化
bash
# 詳細なフック情報を表示
export CLAUDE_DEBUG=1
claude
# すべてのフック実行がログに記録されるフックの一時的な無効化
bash
# すべてのフックを無効化
export CLAUDE_DISABLE_HOOKS=1
claude
# 特定のフックのみ無効化
export CLAUDE_DISABLE_PRE_BASH=1
claude