[BUG] Claude Code in Action / Implementing the hook course teach us proccess.exit(2) + console.error

Resolved 💬 3 comments Opened May 1, 2026 by Med1iK Closed May 1, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Write now I am studying a course Claude Code in Action
Inside that course in section Implementing the hook - we have not actual information.
The course teach us to use
proccess.exit(2) + console.error
if we want to block something inside PretoolUse hook.

But right now we need to use
process.stdout + process.exit(0);

the hooks course teaches process.exit(2) + console.error to block PreToolUse, but this no longer
works in the current version — the correct approach is JSON to stdout with {"continue": false, "stopReason": "..."} +
process.exit(0)

What Should Happen?

Update the information inside the course.

  • you have an antropic certification exame. If inside this exam you use also old information - it is a critical bug

Error Messages/Logs

● Found the issue. The hook at hooks/read_hook.js is correctly detecting .env reads, but it's broken in two ways:

  1. process.exit(2) is the wrong signal. Exit code 2 is only meaningful for asyncRewake hooks. For a synchronous
  PreToolUse hook, it doesn't block the operation — it just indicates an error, and Claude Code falls through and allows
   the read.
  2. console.error writes to stderr, not stdout. Claude Code reads control decisions from stdout. The block signal must
  be JSON on stdout.

  The fix: output {"continue": false, "stopReason": "..."} to stdout, then exit 0:

Steps to Reproduce

Add PreToolHooks

"hooks": {
"PreToolUse": [
{
"matcher": "Read|Grep",
"hooks": [
{
"type": "command",
"command": "node ./hooks/read_hook.js"
}
]
},

Create a read.hooks.js

async function main() {
const chunks = [];
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
const toolArgs = JSON.parse(Buffer.concat(chunks).toString());

// readPath is the path to the file that Claude is trying to read
const readPath =
toolArgs.tool_input?.file_path || toolArgs.tool_input?.path || "";

// TODO: ensure Claude isn't trying to read the .env file
if(readPath.includes('.env')){
console.error("You cannot read the .env file")
process.exit(2);
}
}
main();

Then ask claude to read .env file

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

Code 2.1.126.

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Windows Terminal

Additional Information

_No response_

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗