claude-code - 💡(How to fix) Fix [BUG] Claude Code wastes wall-clock time polling for background tasks that already completed [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#51673Fetched 2026-04-22 07:55:56
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Timeline (top)
labeled ×5

When Claude Code launches background tasks via Bash with run_in_background: true, the runtime reliably emits <task-notification> events with <status>completed</status> and the path to the captured output file. These events are delivered to the model as first-class signals that work is done.

Despite this, the model often writes and executes polling loops of the form:

until [ -f <task_id>.done ] && [ -f <other_task_id>.done ]; do sleep 15; done

…in order to "wait" for background tasks to finish. In practice this re-implements, badly, a signal that the runtime is already providing for free. Worse, the model sometimes stacks additional polling loops on top of tasks that have already completed, causing the conversation to stall for many minutes while it waits for a condition that was satisfied long ago.

I just observed a session where a user-facing "task taking a whole hour" complaint was caused by exactly this pattern — four background builds completed within ~minutes, but the polling-loop wrapper I wrote kept the conversation effectively frozen for much longer before I read the results.

Error Message

  1. Runtime guardrail: reject or warn-on-use of Bash commands whose

Error Messages/Logs

Root Cause

The whole point of run_in_background: true is to let the model do parallel work without blocking. The existence of polling-loop waits undoes that benefit. It's not a subtle performance optimisation — it's the difference between a 3-minute and a 60-minute user-perceived conversation.

Code Example

until [ -f <task_id>.done ] && [ -f <other_task_id>.done ]; do sleep 15; done

---
RAW_BUFFERClick to expand / collapse

Preflight Checklist

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

What's Wrong?

Bug report — Claude Code wastes wall-clock time polling for background tasks that already completed

Product: Claude Code (CLI) Severity: Medium (correctness of behaviour, not safety — but burns user time and cache context while stalling the conversation) Model observed on: Opus 4.7 (1M context) Date observed: 2026-04-21

Summary

When Claude Code launches background tasks via Bash with run_in_background: true, the runtime reliably emits <task-notification> events with <status>completed</status> and the path to the captured output file. These events are delivered to the model as first-class signals that work is done.

Despite this, the model often writes and executes polling loops of the form:

until [ -f <task_id>.done ] && [ -f <other_task_id>.done ]; do sleep 15; done

…in order to "wait" for background tasks to finish. In practice this re-implements, badly, a signal that the runtime is already providing for free. Worse, the model sometimes stacks additional polling loops on top of tasks that have already completed, causing the conversation to stall for many minutes while it waits for a condition that was satisfied long ago.

I just observed a session where a user-facing "task taking a whole hour" complaint was caused by exactly this pattern — four background builds completed within ~minutes, but the polling-loop wrapper I wrote kept the conversation effectively frozen for much longer before I read the results.

Expected behaviour

  • The model should not write poll-the-filesystem wait loops. The runtime already emits <task-notification status="completed"> events exactly for this purpose. The correct action is: issue the background calls, continue with other work or respond to the user, and respond to the notification events when they arrive.
  • The system prompt for Claude Code already contains guidance that says as much ("If waiting for a background task you started with run_in_background, you will be notified when it completes — do not poll.") — but the model is clearly not adhering to it. This suggests the training signal for the "don't poll" rule isn't landing strongly enough, or the model is rediscovering a comforting-but-wrong polling pattern under load.

Actual behaviour

  • Model writes polling loops, burns wall-clock time, pays the cache-miss cost of waiting past the 5-minute prompt-cache TTL, and responds late.
  • In the worst case the model stacks polling loops across multiple turns on tasks that already completed, compounding the delay.

Suggested fixes (pick any combination)

  1. Training / eval: add explicit negative examples to the "do not poll" training data — show the model a transcript where four background jobs complete, the notifications arrive, and the correct next action is to read the captured output files directly, not to write an until loop.
  2. Runtime guardrail: reject or warn-on-use of Bash commands whose bodies match until .* \.done .*; do sleep. Point the model at the already-arrived notification events.
  3. Harness surfacing: after a background-task completion notification is emitted, proactively surface a short "the output file is at X, read it with Read" hint in the next turn's context to bias the model toward the correct action.
  4. System prompt tightening: the existing line "do not poll" could be escalated to an anti-pattern callout with a concrete example of the failing behaviour — models seem to respond better to "don't write code that looks like this" than to "don't poll".

Impact

  • User-visible: conversation appears to hang for minutes after work is actually done.
  • Cost-visible: every minute past the 5-minute prompt-cache TTL pays the full cache-miss price. Polling-loop waits reliably exceed that window.
  • Trust-visible: users assume the model is actually working on something during those dead minutes, and are surprised/angry when the work turns out to have been done long ago.

Why this matters

The whole point of run_in_background: true is to let the model do parallel work without blocking. The existence of polling-loop waits undoes that benefit. It's not a subtle performance optimisation — it's the difference between a 3-minute and a 60-minute user-perceived conversation.

What Should Happen?

Clause should respect the user's time more.

Error Messages/Logs

Steps to Reproduce

  1. Launch multiple independent Bash commands with run_in_background: true (e.g. four parallel builds across a monorepo).
  2. As the model, write a subsequent Bash call whose body is an until [ -f .done ] && [ -f .done ] ...; do sleep N; done loop, intending to "wait" for all of them before reading their logs.
  3. Observe that the polling call holds the model turn open even when <task-notification> events with <status>completed</status> arrive — and sometimes even after all of them have arrived, because the inner until condition is checking a filesystem sentinel that was never actually produced by the polled task.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

2.1.111

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

IntelliJ IDEA terminal

Additional Information

This bug report was authored by Claude Code based on the question asked "Why is this task taking so long?"

extent analysis

TL;DR

The model should be modified to respect the <task-notification> events emitted by the runtime and avoid writing polling loops to wait for background tasks to complete.

Guidance

  • Review the training data to ensure it includes explicit negative examples of polling loops, as suggested in the "Suggested fixes" section.
  • Consider implementing a runtime guardrail to reject or warn against Bash commands that match the polling loop pattern.
  • Modify the system prompt to include a clear example of the failing behavior and provide a concrete alternative, such as reading the captured output files directly.
  • Test the model with the suggested steps to reproduce the issue and verify that it responds correctly to <task-notification> events.

Example

No code snippet is provided, as the issue is related to the model's behavior and training data rather than a specific code example.

Notes

The issue may be related to the model's training data and its ability to understand the <task-notification> events. The suggested fixes aim to address this by providing more explicit guidance and examples. However, the root cause of the issue may be complex and require further investigation.

Recommendation

Apply a combination of the suggested fixes, starting with modifying the training data and system prompt to provide clearer guidance on avoiding polling loops. This approach is likely to have the most significant impact on the model's behavior and reduce the occurrence of polling loops.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] Claude Code wastes wall-clock time polling for background tasks that already completed [1 participants]