[BUG] Hook stderr output is silently swallowed — not visible to user (all hook types)

Resolved 💬 5 comments Opened Mar 12, 2026 by AndrzejPM Closed Apr 20, 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?

Bug

Hook stderr output is never displayed to the user in the terminal, despite the hooks documentation stating that stderr should be visible to the user. This affects all hook types, not just SessionStart.

  • stdout → delivered to Claude as context (works correctly)
  • stderr → silently discarded (bug)

This means there is no mechanism for hooks to communicate anything directly to the user.

Result

  • Claude receives the stdout lines in its context
  • User sees nothing in the terminal from any stderr method
  • Tested across both SessionStart and Stop hook types
  • Tested with bash >&2, tee /dev/stderr, Node.js process.stderr.write(), and console.error()
  • Tested with claude, claude --resume, and multiple session restarts
  • None reach the user's terminal

Prior issues

This was reported in #10808 and #25543 (both closed without resolution — stale/duplicate). The underlying problem remains: there is no working mechanism for hooks to display messages to the user.

Suggested fix

Either:

  1. Fix the bug: pipe hook stderr to the user's terminal (as documented)
  2. Add displayMessage to the hook output schema — a field that Claude Code renders directly in the terminal after the hook completes

Option 1 is the minimal fix and matches existing documentation. Option 2 (from #10808) would be a richer solution.

Environment

  • Claude Code CLI (latest as of 2026-03-12)
  • macOS (Darwin 25.3.0)
  • Tested in zsh terminal, with claude and claude --resume

What Should Happen?

Expected

stderr from hooks should be displayed to the user in the terminal, as documented.

Impact

  • Users cannot get confirmation that setup hooks ran successfully
  • No way to surface warnings (e.g., missing .env, failed health checks) to the user
  • Hook authors following the documented >&2 pattern get no output
  • Affects all hook types — SessionStart, Stop, and likely PreToolUse/PostToolUse as well

Error Messages/Logs

Steps to Reproduce

Reproduction

Setup

.claude/settings.json:

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/test.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/test-stop.js"
          }
        ]
      }
    ]
  }
}

1. Bash hook (SessionStart) writing to stderr

.claude/hooks/test.sh:

#!/usr/bin/env bash
echo "stdout: visible to Claude"
echo "stderr: should be visible to user" >&2

2. Node.js hook (Stop) writing to stderr

.claude/hooks/test-stop.js:

#!/usr/bin/env node
process.stderr.write('[test] Direct stderr write\n');
console.error('[test] console.error message');
console.log('[test] stdout for Claude');

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.74

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

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