[MODEL] Opus 4.6 [1m] uses deprecated TaskOutput(block=true) instead of Read for backgrounded Bash output

Resolved 💬 2 comments Opened Apr 7, 2026 by gorgeguy Closed May 19, 2026

Summary

In a single session, Claude Opus 4.6 [1m] burned ~100 minutes of wall clock poll-spinning the deprecated TaskOutput(block=true, timeout=...) tool against an auto-backgrounded pyright invocation, instead of using Read on the output file path that the harness provided. The TaskOutput tool's own description explicitly says: "DEPRECATED: Prefer using the Read tool on the task's output file path instead. Background tasks return their output file path in the tool result, and you receive a <task-notification> with the same path when the task completes — Read that file directly." The model ignored that notice.

This is a behavior regression: in a prior session on 2026-03-31 with the same trigger (long-running shell command auto-backgrounded by the harness), the model used Read on the output file path correctly and resolved within minutes. Yesterday's session is the first time TaskOutput was used in 61 sessions for this project — quantitatively a sudden, novel behavior with no precedent in the project's history.

Type of Behavior Issue

Claude's behavior changed between sessions / model regressed to a deprecated tool

What was happening

I was running a multi-step task (test migration). Several invocations of uv run --frozen pyright triggered the harness auto-backgrounding feature (which itself appears new — first appeared in this project on 2026-03-31). Each backgrounded command's tool result included an output file path under /private/tmp/claude-{uid}/.../<task_id>.output.

What the model did instead

  1. Loaded the TaskOutput tool via ToolSearch select:TaskOutput,...
  2. Called TaskOutput(task_id="b3b2zcpoa", block=true, timeout=300000) — blocked for ~17 minutes
  3. Got <retrieval_status>timeout</retrieval_status> back
  4. Called TaskOutput(task_id="b3b2zcpoa", block=true, timeout=240000) on the same task_id — blocked another ~16 minutes
  5. Repeated for other backgrounded tasks
  6. Meanwhile, multiple stale pyright processes from earlier retries were piled up consuming 100% CPU each, starving each other

The model never read the output file directly with Read despite the deprecation notice in TaskOutput's own description. It also never ran ps aux | grep pyright to detect the process pileup until the human prompted it.

Expected behavior

When the harness returns "Command running in background with ID: X. Output is being written to: /path/to/output", the model should:

  1. Not load TaskOutput via ToolSearch
  2. Wait for the <task-notification> that arrives in the next user turn
  3. When the notification arrives, Read the output file path directly
  4. Move on

This is exactly what the same model did in a prior session with the same trigger (see comparison below).

Smoking-gun data (sanitized bundle attached as gist)

Bundle: https://gist.github.com/gorgeguy/5ff43371cc93b90c358a9fe538f8cfc3

Tool-call timing for the affected session (231 calls, 188.0 min total):

Bash                 n= 138  total=  62.4m  avg=  27.13s
TaskOutput           n=   4  total=  55.5m  avg= 832.09s   ← regression
ExitPlanMode         n=   2  total=   6.6m  avg= 199.22s   (waiting for human)
AskUserQuestion      n=   1  total=   2.1m  avg= 124.92s   (waiting for human)
Write                n=   8  total=   0.3m
Read                 n=  37  total=   0.0m  avg=   0.05s
Edit                 n=  31  total=   0.0m  avg=   0.03s
Grep                 n=   6  total=   0.0m  avg=   0.03s

Top 6 slowest individual calls (each 16–17 minutes):

17.4m  TaskOutput      {'task_id': 'b3b2zcpoa', 'block': True, 'timeout': 300000}
17.2m  TaskOutput      {'task_id': 'bpmh6nh11', 'block': True, 'timeout': 600000}
17.1m  Bash            uv run --frozen pyright > /tmp/pyright-out.txt 2>&1; ...
17.1m  Bash            time uv run --frozen pyright 2>&1 | tail -3
16.2m  TaskOutput      {'task_id': 'b3b2zcpoa', ...}   ← SAME task_id polled twice
16.0m  Bash            time uv run --frozen pyright 2>&1 | tail -3

That's the same task_id (b3b2zcpoa) being polled by TaskOutput twice in a row, blocking ~33 minutes total on a single task that should have been read from the output file once.

File-system tools (Read/Edit/Grep/Glob/Write) totalled 0.3 minutes combined across 83 calls. The "thoroughness" narrative does not hold up — every minute of the session loss is concentrated in the TaskOutput polling pattern and the pyright process pileup it caused.

Comparison: same trigger, correct behavior in a prior session

Session 2026-03-31 (2d78287b...):

  • Same trigger (long-running shell command auto-backgrounded)
  • Model's first action after the bg message: Read on the output file path
  • Resolution: clean, minutes
  • Did not load or use TaskOutput

Session 2026-04-06 (88e12e66...):

  • Same trigger
  • Model's first action after the bg message: ToolSearch select:TaskOutput, then TaskOutput(block=true, timeout=300000)
  • Resolution: ~100 minutes wasted
  • Used TaskOutput 4 times

The regression boundary is between 2026-03-31 (correct) and 2026-04-06 (broken).

Frequency

Across 61 sessions in this project:

| Marker | Sessions |
|---|---|
| running in background (harness auto-bg triggered) | 2 |
| TaskOutput tool used | 1 (only the affected session) |
| Sessions with bash_avg > 10s | 1 (the affected session) |

So TaskOutput literally went from never-used to 4 calls in one session, and the per-call wall-clock cost is two orders of magnitude higher than every other tool.

Steps to reproduce

I haven't fully isolated this, but the pattern looks like:

  1. Be in a long, high-context session (~190 min, ~230 tool calls when it triggered)
  2. Run a shell command that takes long enough for the harness to auto-background it (e.g., pyright on a moderate-size codebase, or a long uv run invocation)
  3. Observe that the model loads TaskOutput via ToolSearch and then uses it with block=true, timeout=300000 instead of reading the output file the harness already pointed to in the tool result

I expect this is reproducible for anyone who triggers harness auto-backgrounding under Opus 4.6 [1m]; I haven't tested other models.

Related existing issues

These are not duplicates but they're closely related and should probably be cross-referenced:

  • #33872 — "redundant model turn triggered by task_notification after TaskOutput(block=true) already consumed result" — overlaps with the same TaskOutput(block=true) pattern
  • #38574 (closed) — "TaskOutput tool listed as active but deprecated in v2.1.83; new Read-based approach undocumented" — directly relevant: the deprecation has been called out as confusingly documented before
  • #17591 — "TaskOutput returns raw JSONL transcript instead of subagent summary (regression in 2.0.77)" — same theme of TaskOutput regressions

Environment

  • Claude Code: 2.1.92
  • Model: Claude Opus 4.6 [1m] (1M context)
  • Platform: Anthropic API
  • macOS Darwin 25.3.0 / arm64
  • Permission mode: bypassPermissions (--dangerously-skip-permissions)
  • Hooks: only SessionStart and PreCompact (cheap shell commands, not relevant)

Hypothesis

Something in the model's recent training or system prompt changed how it discovers/selects tools when faced with a "Command running in background" tool result. Instead of following the recommended pattern documented in the TaskOutput description itself, the model now:

  1. Loads TaskOutput via ToolSearch (which it didn't even know about until it actively searched)
  2. Calls it with block=true and a multi-minute timeout
  3. Treats <retrieval_status>timeout</retrieval_status> as "I should retry" rather than "I should read the output file or do something else"

The fix on the model side would presumably be: when seeing "Command running in background" in a tool result, don't reach for TaskOutput at all — read the output file path that's right there in the same message.

Impact

High for any session that involves long-running shell commands. Before this regression, the same model handled the same situation correctly. After it, a single regression burned ~60% of a multi-hour session on one tool-selection mistake. Compounded by lack of process-state inspection (multiple stuck pyright processes piled up because the model never thought to ps | grep and kill them), but the root cause is the tool choice.

Bundle contents

The attached gist contains sanitized versions of:

  • environment.txt — CLI version, OS, model, hostnames redacted
  • session-timing.txt — full per-tool breakdown
  • trend.txt — comparison across the last 30 sessions in this project
  • processes.txtps snapshot showing the stuck pyright processes
  • hooks.json — extracted hook config (just bd prime and pm list, harmless)
  • README.md — bundle layout

The full session.jsonl (2.2 MB) is not in the gist because it contains the entire conversation including code I read and edited. I am happy to share it privately if that would help — please let me know how to deliver it.

Reproduction script (sanitized diagnostic)

For others wanting to check whether their own sessions are hitting this: I wrote a small pure-read diagnostic script that parses any session JSONL and reports per-tool durations. It found this regression in <2 seconds. Happy to share if useful for your repro work.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗