[BUG] Hook Regression in 2.0.17-2.0.22 - UI Shows Duplicate Messages for Stop, UserPromptSubmit, SessionStart (worked in 2.0.15)

Resolved 💬 17 comments Opened Oct 15, 2025 by kuzmeech Closed Oct 22, 2025

Bug Description

Hooks show duplicate success messages (4-7x, growing progressively) in versions 2.0.17-2.0.22. The hook executes only once (confirmed via logging by multiple users), making this a UI rendering bug, not an execution bug. This is a regression - the issue was previously fixed in 2.0.15 (issues #3465, #3523 were closed).

Affected Hook Types:

  • Stop hooks (original report)
  • UserPromptSubmit hooks (confirmed in comment #3417082621)
  • SessionStart hooks (reported in comment #3413436283)
  • ⚠️ Likely affects all hook types (unconfirmed)

Version Information

  • Working version: 2.0.15 (Claude Code) - hooks fire once, UI shows one message
  • Broken versions: 2.0.17, 2.0.19, 2.0.20, 2.0.21, 2.0.22 - hook fires once, UI shows multiple duplicate messages
  • Platform: macOS (Darwin 25.0.0 and 25.1.0)
  • Installation method: ~/.local/bin/claude / npx

Steps to Reproduce

  1. Install Claude Code 2.0.17+ (tested through 2.0.22)
  2. Configure any hook (Stop, UserPromptSubmit, SessionStart) in ~/.claude/settings.json:
{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/stop-hook.sh"
          }
        ]
      }
    ]
  }
}
  1. Create a simple hook script that logs execution:
#!/bin/bash
echo "[HOOK] Running at $(date) - PID:$$ PPID:$PPID" >> /tmp/hook.log
  1. Run Claude Code and trigger the hook (ask a question for Stop, submit prompt for UserPromptSubmit, start session for SessionStart)
  2. Observe the output when hook executes
  3. Check /tmp/hook.log - you'll see one entry per hook trigger

Expected Behavior

2.0.15 output (correct):

Stop [~/.claude/stop-hook.sh] completed successfully

Log shows one execution:

[HOOK] Running at Wed Oct 15 15:40:34 EDT 2025 - PID:62337 PPID:51845

Actual Behavior

2.0.17-2.0.22 output (broken):

⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:

Log still shows only one execution (hook fires once, UI renders multiple times):

[HOOK] Running at Fri Oct 17 21:28:16 EDT 2025 - PID:47982 PPID:18583

Key observations:

  • ✅ Hook script runs only once (confirmed via logging with timestamps/PIDs - see comment #3417678973)
  • ❌ UI displays 4-7 duplicate messages (no hook path shown)
  • 📈 Number of duplicates increases progressively during session (4x → 7x → 10x+ → 13x)
  • 🔄 Restarting Claude Code session temporarily resets count to initial value
  • 🐛 This is a UI rendering bug in Claude Code, not a hook execution problem
  • 🔗 Confirmed by multiple users: comment #3414817564 reports hook fires once but UI shows duplicates
  • ⚠️ Affects multiple hook types: Stop, UserPromptSubmit, SessionStart (see comment #3417082621)

UserPromptSubmit example from comment #3417082621:

  • 1st prompt: Output shows 1x ✅
  • 2nd prompt: Output shows 2x
  • 3rd prompt: Output shows 3x
  • 4th prompt: Output shows 4x
  • Pattern continues linearly with each hook trigger

Environment Details

  • Working directory: Not home directory (tested in various project dirs)
  • Git repo: Yes (also tested in non-git directories - same issue)
  • Shell: zsh, bash
  • Terminals tested: iTerm2, Ghostty (terminal-independent issue)

Additional Context

This is a regression of previously fixed issues:

  • #3465 - Claude Code Hook Events Fired Twice When Running from Home Directory (CLOSED)
  • #3523 - Hook Configuration Progressive Duplication (CLOSED)

Regression window: Bug introduced between 2.0.15 (last working) and 2.0.17 (first broken), persists through 2.0.22 (latest as of 2025-10-17).

Workaround

The only effective workaround is to downgrade to 2.0.15 (last working version):

npx @anthropic-ai/claude-code@2.0.15

Note: Lock file deduplication in hook scripts does NOT fix this issue, as the hook executes only once but the UI renders the output multiple times (UI rendering bug). See comment #3417678973 for configuration analysis proving this.

---

Community Confirmations

This issue has been independently confirmed by multiple users:

  • @kylesnowschwartz - Confirmed Stop hook duplication
  • @acidtech - Confirmed accumulation pattern, noted it stores previous hook responses
  • @SaitoPhoenix - Confirmed hook fires once but output renders multiple times (v2.0.20)
  • @bakud - Confirmed same issue
  • @lsmith090 - Confirmed affects SessionStart and UserPromptSubmit hooks
  • @DAddYE - Detailed confirmation of UserPromptSubmit hook accumulation pattern (v2.0.21)

View original on GitHub ↗

17 Comments

kuzmeech · 9 months ago

Additional Testing

Confirmed this regression reproduces across multiple terminal emulators:

  • iTerm2 (latest): Stop hook fires 3-4 times ❌
  • Ghostty (1.2.2): Stop hook fires 3-4 times ❌

This confirms the issue is in Claude Code 2.0.17 itself, not terminal-specific.

Terminal Versions Tested

  • iTerm2: Latest stable release
  • Ghostty: 1.2.2 (stable channel, build mode: ReleaseFast)
  • macOS: Darwin 25.0.0

The behavior is consistent across all terminals - hooks execute multiple times with the same PPID, suggesting a race condition or duplicate event emission in the Claude Code hook system.

kuzmeech · 9 months ago

Severity Update: Progressive Duplication

The duplication gets progressively worse during a session:

Observed Behavior in 2.0.17

From a single response, the stop hook fired 13 times:

⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:
⎿  Stop hook succeeded:

This is progressive duplication - the same behavior as the previously fixed issue #3523. The number of hook executions increases over the session lifetime.

Comparison

  • 2.0.15: 1 execution (correct) ✅
  • 2.0.17: 3-4 executions initially, escalating to 13+ executions

This severely impacts usability:

  • 13 notification sounds playing simultaneously
  • 13 speech synthesis processes saying "Done with..."
  • Significant performance degradation
  • Makes the hook system unusable in long sessions

This is the exact same progressive duplication pattern from #3523, which suggests the fix was lost during a refactor or merge.

kylesnowschwartz · 9 months ago

Thanks for raising this. I noticed my stop hook notifications were going crazy since the update. This explains it.

acidtech · 9 months ago

It is a direct accumulation of previous stop hooks. No idea HOW this kind of thing could happen. It literally has to be storing the previous json responses. I have a systemMessage in my Stop hook and each message shows the token usage. After each Stop I get ALL the other stop systemMessages(with their original token usage values) and then the new one. It accumulates DIRECTLY with EACH AND EVERY Stop hook. Seriously guys, you need to STOP relying on Claude code writing and validating your code. IT LOVES to restore old regressions because it DOESNT DELETE CODE. It ends up find that old code it "took out" at some point in the future and thinks "this should be added back in" derp derp. You need to CLEAN OUT ALL YOUR DEAD CODE SO THIS KIND OF GARBAGE REVERSION CAN'T HAPPEN. There is ZERO chance of a exact duplication of an old regression UNLESS YOU FAILED TO CLEAR OUT THE OLD DEAD CODE.

The more this happens the more it seems you guys are just VIBE coding Claude Code. Get your act together. This is just pitiful.

kuzmeech · 9 months ago

Still reproduces in fresh 2.0.20, but seemingly with a bit lesser frequency, but can still get to 10 repetitions.

SaitoPhoenix · 9 months ago

v. 2.0.20
I've observed the same issue, but it's not that the hook itself is firing multiple times. It's that the hook output is rendering multiple times. I run a script that simply logs the JSON input when the hook triggers, and I'm only getting one log per call. However, if I turn on my verbose logging which outputs details to the terminal (via systemMessage), my terminal becomes littered with systemMessages that repeat on every, single, hook.

bakud · 9 months ago

same here 🥹

lsmith090 · 9 months ago

same here, but I've seen it happen with SessionStart and UserPromptSubmit hooks as recently as today. They would both trigger two, if not more times.

kuzmeech · 9 months ago

same in fresh 2.0.21 - accumulated to 5 now in the same session

DAddYE · 9 months ago

I can confirm the same accumulation behavior affects UserPromptSubmit hooks (in addition to the Stop hooks described here).

Environment

  • Version: Claude Code 2.0.21
  • OS: macOS (Darwin 25.1.0)
  • Hook Type: UserPromptSubmit

Symptom

Same progressive accumulation pattern as Stop hooks:

  • 1st prompt: Hook fires 1x ✅
  • 2nd prompt: Hook fires 2x
  • 3rd prompt: Hook fires 3x
  • 4th prompt: Hook fires 4x
  • 5th prompt: Hook fires 5x
  • ...and so on

Hook Configuration

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/user-prompt-submit.sh",
            "timeout": 2
          }
        ]
      }
    ]
  }
}

Hook Script Example

#!/usr/bin/env bash
set -euo pipefail

main() {
    echo "AGENT & SKILL SELECTION REMINDER:"
    echo "- Agent selection: haiku (fast/cheap), sonnet (standard), opus (complex)"
    echo "- Skills auto-invoke based on file types and keywords"
    echo "- Use Task tool for multi-step work; never use skill names as subagent_type"
    echo "- Review ./.claude/CLAUDE.md for complete guidelines"
}

main "$@"

The hook script outputs plain text (exit code 0), which should be injected once per prompt, but instead accumulates with each submission.

---

This suggests the 2.0.17+ regression affects multiple hook types (Stop, UserPromptSubmit, and likely others), not just Stop hooks specifically.

kuzmeech · 9 months ago

Configuration Analysis: Stop Hook Bug is Not User-Caused

I've analyzed my complete Claude Code setup to determine if my configuration could be causing the duplicate message bug. Conclusion: My setup cannot cause this issue.

Evidence: Hook Executes Only Once

Log entries from my stop hook show single execution per response:

[STOP HOOK] Running at Fri Oct 17 21:28:16 EDT 2025 - PID:47982 PPID:18583 PWD:~/.../project

No duplicate log entries = hook fires once, but UI shows 4-7 duplicate messages.

My Hook Configuration

settings.json - Standard configuration:

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/stop-hook.sh"
          }
        ]
      }
    ]
  }
}

stop-hook.sh - Has deduplication logic (added for old bugs #3465, #3523):

#!/bin/bash
# Timestamp-based deduplication
NOW=$(date +%s)
LOCK_FILE="/tmp/claude-stop-hook-$PPID.lock"
LOCK_TTL=3  # seconds

if [ -f "$LOCK_FILE" ]; then
    LOCK_TIME=$(cat "$LOCK_FILE" 2>/dev/null || echo 0)
    TIME_DIFF=$((NOW - LOCK_TIME))
    if [ "$TIME_DIFF" -lt "$LOCK_TTL" ]; then
        echo "[STOP HOOK] Skipping duplicate" >> "$LOG_FILE"
        exit 0
    fi
fi
echo "$NOW" > "$LOCK_FILE"

# ... rest of hook logic (notifications, etc)

Result: Lock file deduplication never triggers - no "Skipping duplicate" messages in logs, proving hook fires only once.

Why This Proves It's a Claude Code UI Bug

  1. Hook executes 1x (proven by logs) → UI renders 4-7x (visible output)
  2. Lock mechanism never activates → No actual duplicate executions
  3. Bug persists across versions 2.0.17-2.0.22 → Not configuration-dependent
  4. Same behavior in multiple terminals (iTerm2, Ghostty) → Not terminal-specific
  5. Workaround is downgrading (2.0.15 works perfectly) → Regression in Claude Code itself

Additional Notes

  • UserPromptSubmit hook also configured (Python script, clean exit, no stdout)
  • Custom statusLine command configured (unrelated to Stop hook)
  • No unusual permissions or settings
  • Bug appears identical whether using npx or installed version

The duplication occurs in Claude Code's output rendering layer, not in hook execution. My configuration is clean and cannot cause this issue.

kuzmeech · 9 months ago

Tested 2.0.22 (released 2025-10-17): Bug still present - same UI duplication behavior.

kuzmeech · 8 months ago

looks like not reproducing in 2.0.24. I'll watch next release too.

DAddYE · 8 months ago

I confirm it doesn't happen in 2.0.24, however the message is totally
ignored :/

On Tue, Oct 21, 2025 at 12:04 AM kuz8 @.***> wrote:

kuzmeech left a comment (anthropics/claude-code#9602) <https://github.com/anthropics/claude-code/issues/9602#issuecomment-3425049846> looks like not reproducing in 2.0.24 — Reply to this email directly, view it on GitHub <https://github.com/anthropics/claude-code/issues/9602#issuecomment-3425049846>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAABTCKD7QPMUG2DRKTU64D3YXLGJAVCNFSM6AAAAACJJMI476VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTIMRVGA2DSOBUGY> . You are receiving this because you were mentioned.Message ID: @.***>
kylesnowschwartz · 8 months ago

I believe this particular issue is fixed for me - will continue to monitor for now.

kuzmeech · 8 months ago

Also looks fixed in 2.0.25

github-actions[bot] · 8 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.