[BUG] Resuming a session interrupted during a usage-limit retry wait answers the pending message with a synthetic "No response requested."

Status Open
Reported on v2.1.289
Maintainer reply None cached
Activity 1 comment · opened Oct 6, 2026

Preflight Checklist

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

What's Wrong?

With persistent retry mode on (CLAUDE_CODE_RETRY_WATCHDOG=1), a turn whose request gets the usage-limit 429 sits in the retry wait (Weekly limit reached · Retrying in 2h (12:16pm) · attempt 1/300). If the session is exited during that wait and resumed with claude --resume <id>, the resumed process writes a synthetic assistant message, No response requested. (model <synthetic>), directly after the user message that turn was answering. Nothing is sent on resume. In the follow-up request I inspected, the history carries that pair, so it now reads as if the message needed no answer, and nothing re-sent the message while I watched. (How a real model then treats it is an inference; my reproduction used a mock that returns canned replies.)

I exit and resume limit-blocked sessions routinely, to continue them on another account.

It happens for a message typed by the user and for a message from another local session (SendMessage) alike. The second case is worse:

  • the receiving user sees only a collapsed one-line preview of the peer message, so may not notice it was never answered;
  • the sending session's SendMessage result said the message is "in that session's inbox, not yet read by its Claude", and promises a [Cross-session delivery notice] only if the session holds or refuses it. A message answered by a synthetic reply is neither, and no notice reached the sender while I watched.

This may be the same underlying behaviour as #57195, which also describes an interrupt followed by a resume inserting the sentinel after an orphaned user turn and asks for the insertion to stop. This report adds a controlled CLI reproduction through a usage-limit retry wait, and the peer-message case, where the pending request comes from another session that believes it was delivered. Related reports of the sentinel: #53260 (closed as not planned; the synthetic message shown as if the model wrote it), #89265 and #93957 (auto-resume and interrupts).

What Should Happen?

On resume, a user or peer message whose turn was cut off by the limit wait should be treated as unanswered: no No response requested. after a message that did request a response. Either re-queue it so it is sent with the next turn, or mark the turn as interrupted in a way the model can see. For a peer message, a [Cross-session delivery notice] to the sender when it is dropped unanswered would also help.

Error Messages/Logs

# Records from the reproduction below, as record type then content (contents shortened):
queue-operation enqueue   <cross-session-message from="uds:…" from-name="b-ba" from-mode="prompting">PEER-PING-4 …</cross-session-message>
queue-operation dequeue
user (origin.kind "peer") Another Claude session sent a message: <cross-session-message …>PEER-PING-4 …
   [request gets HTTP 429 rate_limit_error; screen: Weekly limit reached · Retrying in 2h (12:16pm) · attempt 1/300]
   [/exit, then claude --resume <id>]
assistant (model <synthetic>) No response requested.

# The sender's SendMessage result for that message:
{"success":true,"message":"“fourth ping” → a-9a (another Claude session on this machine; in that session's inbox, not yet read by its Claude — a [Cross-session delivery notice] follows if that session holds it (usually a different permission mode) or refuses it)","msg_id":"…"}

Steps to Reproduce

This needs persistent retry mode: start the limited session as CLAUDE_CODE_RETRY_WATCHDOG=1 claude. In my test without it, the interactive session ended the turn at once with API Error: Request rejected (429), so it never entered the retry wait this report is about.

The two cases are alternatives; each starts fresh.

Typed case:

  1. Start session A on an account at its weekly usage limit, with the variable above.
  2. Send any message. A shows Weekly limit reached · Retrying in ….
  3. Run /exit, lift the limit or wait for it to reset, and run claude --resume <A's session id>. No request is made and your message shows unanswered.
  4. Send another message. The transcript now has No response requested. straight after your first message (on 2.1.289 it was already there right after the resume), and the request for the new message carries that pair.

Peer case:

  1. Start session A as above, on the limited account, and leave it idle.
  2. Start session B on the same machine with the same config directory, on an account that can still make requests. The built-in ListAgents and SendMessage tools let B reach A.
  3. Have B send A a message. A turns it into a user turn, gets the 429 and waits.
  4. /exit A, then resume it as in the typed case. The peer's message is followed by No response requested., A does not answer it, and B receives no notice. (A's peer name changes on every resume; re-run ListAgents in B.)

I measured the peer case on 2.1.289 only, where the synthetic record was already there right after the resume. I have not re-run it on 2.1.291; there I expect it to appear when the next message is sent, as in the typed case, but that is untested.

These steps describe the real service; my measured runs used the mock described below.

Tested exit: /exit only. Not tested: Ctrl+C, Ctrl+D, SIGTERM, claude --continue.

Claude Model

Not sure / Multiple models

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.291 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

Both cases were reproduced on 2.1.289, and the typed case again on 2.1.291 (where the synthetic record is written when the next message is sent), against a local mock of the Messages API that returns the usage-limit 429 with the same status, body and anthropic-ratelimit-unified-* headers as a real capture. The real API's behaviour is inferred, not measured. The peer case was first seen in a real session: the message arrived on 2.1.285, and the resume that wrote the synthetic record ran 2.1.289; it shows the same relevant transcript pattern (peer enqueue, dequeue, user record, then the synthetic reply after the resume). That the cause is the same retry-wait path is an inference: the interactive transcript records no retry status.

Related: #53260, #57195, #89265, #89995, #93957 (the same sentinel, other triggers); #87323 (a cross-session message written to the transcript but kept out of the model's context); #89462 (store-and-forward between sessions). Companion report: #100003 covers messages that were never taken off the queue; this one covers a message that had already become a user turn.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗