Claude writes Monitor log watchers (`tail -F | grep | while … break`) that never exit, so the task shows "Running" up to 30 min after the build ends
Preflight Checklist
- [x] I have searched existing issues for similar behavior reports
- [x] This report does NOT contain sensitive information (API keys, passwords, etc.)
Type of Behavior Issue
Other unexpected behavior
What You Asked Claude to Do
Make UI changes in an iOS app (Swift/UIKit) and verify them with xcodebuild build and xcodebuild test, working in the Claude desktop app's Code tab.
What Claude Actually Did
Claude ran xcodebuild in the background, writing to a log that ends with an exit <code> line, then started a Monitor to stream errors and the end of the run:
tail -n +1 -F "$S/test.log" | grep -E --line-buffered "error:|: error|TEST SUCCEEDED|TEST FAILED|^exit " | while IFS= read -r l; do echo "$l" | cut -c1-300; case "$l" in exit*) break;; esac; done
break ends only the while loop. tail -F keeps following the finished log and grep keeps waiting on it. Neither writes again, so neither gets SIGPIPE, and the shell waits for every stage of the pipeline. The Monitor therefore runs until its timeout.
Observed: a test run finished in about 2 minutes (** TEST FAILED **, exit 65) and the session finished its reply a minute later, but the Background tasks panel kept showing the Monitor as "Running" for 29m 47s. The thread looked stuck. The same pattern (with tail -F or tail -f) appears in at least 6 sessions over 5 days in this project.
Expected Behavior
A watcher that ends when the run ends (for example, one that kills its tail before break), or no watcher at all: Bash run_in_background already notifies Claude when the command exits.
Files Affected
Permission Mode
I don't know / Not sure
Can You Reproduce This?
Sometimes (intermittent)
Steps to Reproduce
- Ask Claude to build or test a project whose build takes a minute or more.
- Claude starts the build in the background and a
tail -F … | grep … | while … breakMonitor on its log. - After the build ends, the Monitor stays "Running" in Background tasks until its timeout.
Minimal shell demo of why it can't end:
log=$(mktemp); (sleep 1; echo 'exit 0' >> "$log") &
tail -n +1 -F "$log" | grep --line-buffered '^exit ' | while read -r l; do echo "$l"; break; done
# prints 'exit 0', then doesn't return until tail is killed
Claude Model
Opus
Relevant Conversation
Impact
Low - Minor inconvenience
Claude Code Version
2.1.288 (Claude Code), bundled with Claude desktop app 2.37337.1
Platform
Anthropic API
Additional Context
- Claude desktop app (Code tab), macOS 26.5.2, Apple M1 Max, model Opus 5.5.
- After a user-level rule told Claude to kill
tailitself, the fixed watcher still hung: the built-in grep→ugrep shim holds back the last line of a live pipe when the pattern contains|, so the finalexitline never reached the loop. That's a separate bug in the shim. - Related: #91450 (no signal when a followed log's writer dies), #95242 (orphaned
tail -Fafter TaskStop).