This is a detailed correction/retraction, not a bug report requiring a GitHub issue. The user has identified that their original issue was caused by their own code (a quadratic string operation in their hook), not Claude Code. However, they do identify tw

Status Open
Maintainer reply None cached
Activity 0 comments · opened Jul 28, 2026

Bug Description
CORRECTION — root cause found, and it was mine

Please disregard my earlier report ("Edit/Write tool results delayed 50-600s while Read stays at 0.1s; no local cause found after 10 exclusions"). The cause was local: a quadratic string operation in my own PostToolUse hook. No Claude Code defect is involved in the stall. I am posting the correction because the reason my investigation went wrong is reusable, and because one unrelated finding in the original report does still stand.

Root cause

My repo has a shared hook entry point, .claude/hooks/hook-input.sh, created Jul 26 10:13 UTC — four minutes before the first stall at 10:18:16. It tested the stdin payload for emptiness with:

[ -z "${raw//[[:space:]]/}" ]

bash's pattern substitution is quadratic in the number of matches: each match rebuilds the result string. PostToolUse payloads carry tool_response — the full file content for Edit/Write, the full output for Bash — and those are dense with whitespace matches.

Measured outside the harness (/bin/bash 3.2.57, macOS):

┌──────────────────────────┬────────────────────┐
│ payload │ duration │
├──────────────────────────┼────────────────────┤
│ 64 KB JSON │ 62.7 s of pure CPU │
├──────────────────────────┼────────────────────┤
│ 256 KB JSON │ > 120 s │
├──────────────────────────┼────────────────────┤
│ 64 KB with no whitespace │ 0.03 s │
└──────────────────────────┴────────────────────┘

Fix — a case glob, linear: 2 MB in 0.11 s. Before/after on the identical file and edit: 124.5 / 127.2 s → 0.1 s.

Why "hooks: 20-46ms" in my exclusion table was wrong

This is the part worth keeping. I did measure the hooks, and the number was real — I measured them with a hand-made payload of a few hundred bytes. The defect is quadratic in payload size, so a small probe reports a healthy hook with complete confidence. The exclusion looked rigorous and was worthless.

What would have caught it in one step, and what I would do first next time: during a stall, look at what child processes the harness has alive.

ps -axo pid,ppid,stat,command | awk '$2 == <harness-pid>'

The hook was there for the entire stall duration, spinning at R. A sample of that subshell showed 100 % of frames in bash userland — no syscall leaf, nothing blocking. Meanwhile the harness process itself sat in kevent, asleep, which is what made it look like a harness-side wait. It was asleep because it was waiting for my hook.

Two more of my conclusions were wrong and follow from the same mistake:

  • "same binary, different behaviour on two days" — correct observation, wrong inference. The binary did not change; my repo did, and the change was not in the …

Note: Content was truncated.

View original on GitHub ↗