[BUG] Foreground `sleep` block fires constantly — model polls background tasks the harness already promised to notify about

Status Open
Reported on v2.1.266
Maintainer reply None cached
Activity 0 comments · opened Sep 9, 2026

Preflight

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

Related but distinct: #90475, #87920, #86085 and #90930 are all about what the block message recommends next (unbounded until-loops, Monitor when Monitor is disabled, subagent lifecycle). This issue is about how often the block fires at all — the model reaches for foreground sleep reflexively, including in cases where there is nothing to wait for.

What's Wrong?

The Bash tool description already states the rule up front:

run_in_background runs the command detached: it keeps running across turns and re-invokes you when it exits. No & needed. Foreground sleep is blocked; use Monitor with an until-loop to wait on a condition.

Despite that, the model composes a foreground sleep anyway, and the guidance only lands as a rejection after the call. In this session it happened one tool call after the harness had explicitly said no waiting was needed.

The sequence:

  1. Started a long eval run with run_in_background: true. The tool result said:

> Command running in background with ID: bvnm1qqbz. Output is being written to: …/tasks/bvnm1qqbz.output. You will be notified when it completes.

  1. Next tool call, the model issued sleep 90; tail -c 1500 … to poll that same task.
  1. Blocked:

> Blocked: sleep 90 followed by: tail -c 1500 … To wait for a condition, use Monitor with an until-loop (e.g. until <check>; do sleep 2; done). To wait for a command you started, use run_in_background: true. Do not chain shorter sleeps to work around this block.

The block was correct. The poll was also entirely unnecessary — the task had already promised a completion notification, so the right action was to do nothing. The model still spent a round-trip on it.

The user's report, verbatim: "you hit this a lot, like A LOT." This is not a one-off; it recurs across sessions.

Why this is worth separating from the existing reports

The four related issues assume the block is a fine outcome and argue about the replacement advice. This one is that the block fires far too often to be a good signal:

  • Every occurrence costs a full round-trip and pollutes the transcript with a rejection.
  • The rule is already in the tool description, so restating it in the rejection is not changing behavior.
  • The most common trigger appears to be polling a task the harness has already committed to notifying about — a wait that should never have been composed, and which no until-loop or Monitor call improves either.

Suggestions

Either would help; they are not exclusive.

  1. Make the pending-notification state visible at composition time — e.g. keep a short "N background tasks running; you will be notified" line in context — so polling reads as redundant rather than as the obvious next move.
  2. Treat the frequency itself as a model-behavior regression rather than something the rejection message can fix. The instruction exists and is not being followed.

Environment

  • Claude Code 2.1.266
  • macOS (Darwin 25.6.0), zsh
  • Model: Claude Opus 5

View original on GitHub ↗