CC-301c · Module 1
Hook Debugging
4 min read
Hooks fail silently. This is by design — a failing hook should not crash Claude Code or block the user's workflow. But silent failure means you need active debugging strategies, because the symptom of a broken hook is not an error message. The symptom is nothing happening. Claude finishes a task, the stop hook was supposed to run type checking, but no type errors are reported and no auto-commit happens. Was the code clean? Or did the hook fail to execute?
The first debugging step is always verification of execution. Add a console.error("Hook fired") at the very first line of your hook script. Console.error goes to stderr, which Claude ignores but which appears in the Claude Code debug logs. If you do not see "Hook fired" in the logs, the hook is not executing at all — the problem is in your settings.json configuration, not in your hook script.
The second most common failure is incorrect tool matching. Your hook is configured to fire on "file_edit" events but the tool name in the Claude Code runtime is "Edit" or "Write." The tool name must exactly match what Claude Code uses internally. Check the Claude Code documentation for the exact tool names — they are case-sensitive and use specific naming conventions that do not always match what you might guess.
The third failure mode is environment mismatch. Your hook script works when you run it manually from the terminal but fails inside Claude Code because the PATH is different, a required environment variable is missing, or the working directory is not what you expected. Hook scripts run in the Claude Code process environment, which may not have your shell profile loaded. Use absolute paths for all binaries, explicitly set required environment variables, and never assume the working directory. These are the same practices you would apply to any CI/CD script, because hooks are fundamentally CI/CD scripts that run locally.