Harness writes synthetic "No response requested." turns when API returns empty content on auto-resume

Resolved 💬 2 comments Opened Apr 25, 2026 by talonstump27-wq Closed Jun 16, 2026

Summary

Claude Code writes synthetic assistant-turn records to the transcript JSONL with the literal text No response requested. when an API call for that turn returns a zero-content response. The UI displays the synthetic record as if the model produced it, making the model appear stuck. Continuing the session sometimes causes subsequent real turns to echo the stub back, compounding the appearance of a stall.

Transcript record shape

{
  "type": "assistant",
  "message": {
    "role": "assistant",
    "model": "<synthetic>",
    "stop_reason": "stop_sequence",
    "stop_sequence": "",
    "content": "No response requested."
  }
}

model: "<synthetic>" indicates the harness wrote the record without a real API exchange. The stop_sequence: "" is suspicious — if that empty string is actually passed to the API as a stop sequence, it would match at position 0 of any response and force immediate zero-token termination.

Trigger pattern

15 stubs across one user's transcripts on this machine. Distribution by what immediately precedes the synthetic record:

| Preceding event | Count |
|-----------------|-------|
| User turn | 11 |
| queue-operation | 4 |

100% of the user-preceded stubs are preceded by exactly the same user turn: Continue from where you left off. — the harness's auto-resume prompt, not user-typed. The queue-operation cases are the same pattern after dequeuing batched user messages.

So the trigger is: long-running tool/skill call completes (or session resumes) → harness injects auto-resume → API returns empty → harness stubs No response requested.

Reproducibility

Hits across short and long sessions (106 lines to 1298 lines). Not strictly correlated with context length, though large system-prompt surface (cowork plugin enabled, ~80 skills + ~250 deferred MCP tools loaded) seems to make it more frequent.

Diagnostic recipe

Search any user's transcripts to confirm:

import json, os
for root, _, files in os.walk(os.path.expanduser("~/.claude/projects")):
    for f in files:
        if not f.endswith(".jsonl"): continue
        with open(os.path.join(root, f), "r", encoding="utf-8") as fh:
            for i, line in enumerate(fh, 1):
                try: obj = json.loads(line)
                except: continue
                msg = obj.get("message", {})
                if isinstance(msg, dict) and msg.get("model") == "<synthetic>":
                    print(f"{f}:{i}", msg.get("content"))

Questions for the team

  1. Is empty stop_sequence: "" ever actually passed to the API? If so, that's the root cause.
  2. When the API returns empty content, why does the harness write a synthetic stub instead of retrying with backoff or surfacing the error to the user?
  3. Could the auto-resume prompt include enough context that an empty response is less likely (e.g. the last assistant tool-use, or a recap of the in-progress task)?

Environment

  • Claude Code on Windows 11 (PowerShell + Git Bash)
  • Opus 4.7 (1M context)
  • Large skill/MCP surface (cowork plugin)

Impact

Reported hours of lost work per session for long skill invocations (writing-plans, foundation-research). No actionable error surfaced — the user sees only a model that appears to have given up.

Workarounds users have to apply

  • Avoid queueing messages while a skill runs
  • Manually retype the prompt when the stub appears (don't let it stay in history)
  • Start fresh sessions if the stub appears more than once in a row

View original on GitHub ↗

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