CLAUDE LABJP
OPUS — Claude Opus 4.7 is generally available, improving software engineering, long-running coding, and higher-resolution visionAPIKEY — You can now set an expiration on API keys in the Console, with email reminders before keys valid for 7+ days expireREFLECT — A monthly recap at Settings > Reflect shows your top topics, most active day, and peak hour (beta)M365 — The Microsoft 365 connector now supports write tools for email, calendar, and OneDrive/SharePoint filesCOWORK — Cowork expands to web and mobile, bringing Chat and Cowork into one shared home across devicesDESIGN — Claude Design, a new Anthropic Labs product, lets you co-create designs, prototypes, slides, and one-pagersOPUS — Claude Opus 4.7 is generally available, improving software engineering, long-running coding, and higher-resolution visionAPIKEY — You can now set an expiration on API keys in the Console, with email reminders before keys valid for 7+ days expireREFLECT — A monthly recap at Settings > Reflect shows your top topics, most active day, and peak hour (beta)M365 — The Microsoft 365 connector now supports write tools for email, calendar, and OneDrive/SharePoint filesCOWORK — Cowork expands to web and mobile, bringing Chat and Cowork into one shared home across devicesDESIGN — Claude Design, a new Anthropic Labs product, lets you co-create designs, prototypes, slides, and one-pagers
Articles/Claude Code
Claude Code/2026-05-24Intermediate

Recovering from Claude Code's 'Tool result could not be submitted'

What 'Tool result could not be submitted' really means in Claude Code, and the practical recovery steps I rely on after years of running indie apps with 50M+ downloads through it.

Claude Code186ErrorsTool Use8MCP42Troubleshooting11

You are halfway through a long Bash run or waiting on a slow MCP server, and the terminal suddenly prints a flat red line: Tool result could not be submitted. If you use Claude Code daily, you have probably seen it at least once. As an indie developer who has run an app business with over 50 million downloads through Claude Code, I have watched this exact failure swallow entire afternoons, especially in periods when I was adding new MCP servers every other day.

The message is short and the temptation is to mash /cancel or close the terminal. Both of those reactions tend to make things worse. Let me walk you through the failure mode the way I actually think about it on a Tuesday afternoon.

When this error shows up

The error fires when Claude Code finishes a tool call (Bash, Read, Edit, an MCP tool, or your own custom MCP) but cannot deliver the result back to Claude. From my own logs, the common triggers are:

  • An MCP server returning an unexpectedly large JSON payload (hundreds of KB up to a few MB) in a single response
  • A casual Bash call like grep -r or find whose output balloons to tens of thousands of lines
  • Your network blinking out mid-stream, even for a second, while the result is being sent
  • A /cancel press followed too quickly by a new prompt

In every case, the tool itself did its job. What failed is the layer that hands the result back to Claude. That distinction matters when you decide how to recover.

Surface cause vs real cause

The instinct is to blame the tool or the MCP server. After years of debugging, I have learned that the real culprits are almost always one of three things:

  1. Result payload size. Claude Code enforces a practical ceiling on the size of a single ToolResult. Cross it and the message is dropped silently with this error.
  2. ToolUseId / ToolResultId mismatch. If you cancel one call and immediately start another, the pending ToolResult can end up orphaned, and the next call gets rejected.
  3. Streaming disconnects. A momentary VPN flap or Wi-Fi roam is enough for the client to give up on the result.

Treat the error as a delivery problem, not a tool problem. That mental model alone fixes 80% of the panic.

Immediate recovery, without burning your session

When the error appears, the goal is to preserve as much of your hard-earned context as possible. Here is the order I follow:

  1. Press Enter once with no extra input. Occasionally the client will retransmit the orphaned result.
  2. If that does not help, run /compact. This collapses the current conversation into a compact summary and resets the internal session state into something coherent.
  3. After /compact, ask Claude in plain language to continue what it was doing. If you reissue the same tool call, change one argument (for example add -maxdepth 3 to find) so you do not reproduce the original blowup.
  4. If the session is truly stuck, open a fresh Claude Code window and paste the /compact summary as the first message. This is far less painful than starting from zero.

Resist the urge to spam /cancel. Repeated cancels usually deepen the inconsistency and make recovery harder.

Root cause fixes by pattern

Recovery handles today. Prevention handles tomorrow.

MCP responses that are too big

This is the failure mode I have hit most often. If you build an MCP server with a tool like search_files or list_tickets, the result size depends entirely on the caller's query. A bad query can push you past the ceiling instantly.

// Before: returns everything in one shot
server.tool("search_files", async ({ query }) => {
  const all = await db.search(query);
  return { content: all.map(toJSON) };
});
 
// After: hard cap plus cursor-based continuation
server.tool("search_files", async ({ query, cursor, limit = 20 }) => {
  const page = await db.searchPaged(query, { cursor, limit });
  return {
    content: page.items.map(toJSON),
    nextCursor: page.nextCursor,
  };
});

Two rules I keep: cap each tool response at a few tens of KB, and expose a cursor so Claude can ask for the rest in subsequent calls. Claude is excellent at iterating; one fat response is slower in practice than three lean ones.

Bash output that overflows

The same ceiling applies to Bash output. Before pressing Enter on a command, take a beat and think about how many lines it might emit.

# Risky: unknown output size
grep -r "TODO" .
 
# Safer: measure first, sample second
grep -rl "TODO" . | wc -l
grep -rl "TODO" . | head -50
 
# Or stash the full result and return a summary
grep -r "TODO" . | head -200 > /tmp/todo.txt && wc -l /tmp/todo.txt

In my own projects I keep a .claude/commands/safe-grep.md slash command that bakes these guards in, so I never have to remember them in the moment.

ToolUseId / ToolResultId mismatch

If you press /cancel and then immediately type a new prompt, the unsent ToolResult lingers and the next tool call can fail to register. My fix is small but disciplined: after any /cancel, the very next message I send is a sentence like "stop here, summarize where we are, and wait." It feels like a detour, but it is the fastest path back to a clean state.

Streaming disconnects

Most disconnects I see happen during VPN reconnects or when a laptop roams between Wi-Fi access points. For any long-running task (a migration, a heavy refactor, a large build), I now:

  • Pin the connection to wired Ethernet or a known-stable Wi-Fi network
  • Pause cloud sync and background updates that might saturate the link
  • Run long Bash jobs under nohup or inside tmux, then Read the result file once it lands

My grandfathers were both carpenters who built and restored shrines in Japan. They taught me, just by example, that long jobs are won in the preparation. The same is true for long Claude Code sessions.

A safety net when nothing else works

If you reach the point where the session refuses to recover, here is my last-resort routine:

  1. Try claude /resume in a new tab to see if the previous session can be reattached
  2. If not, open a fresh session and feed it a pre-written summary like cat .claude/last_session_summary.md
  3. Add a line to your project's CLAUDE.md instructing Claude to start each recovery by running git status and git log -3 and reporting the current state

That third item is plain but powerful. Treat it as a handover note for your future self, the same way I think about leaving something useful behind for my kids who live apart from me.

One small thing to try today

If this error has bitten you more than once, paste these two lines into your project's CLAUDE.md today:

- For Bash grep/find, always run `wc -l` first to check the size before fetching results
- MCP tools must paginate; never return more than ~20 items per call

That alone has cut the frequency of "Tool result could not be submitted" by more than half in my own workflow. Thanks for reading, and I hope this saves you the afternoon it once cost me.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-04-26
Untangling Claude Code's 'Authorization Failed' Error — OAuth, MCP, and Dynamic Client Registration
Why Claude Code suddenly throws 'authorization failed' or 'incompatible auth server: does not support dynamic client registration', and what to actually do about it. A practical walkthrough of OAuth, MCP server requirements, and the real fixes that work in production.
Claude Code2026-06-27
When an OAuth Token Expires, Your Unattended Run Has Nowhere to Go — A Token-Lifecycle Design That Keeps Remote MCP Alive
Remote MCP connectors are authorized via OAuth, but access tokens are short-lived. Interactive sessions can re-authorize in a browser; an unattended scheduled run has nobody to click the dialog. Here is a token-lifecycle design that owns expiry and refreshes ahead of time.
Claude Code2026-06-21
When Claude Code Still Writes Stale Code With Context7 Installed — Verifying the Injection Actually Worked
You installed Context7 MCP, yet Claude returns code against a deprecated API. Most of the time the documentation injection silently no-ops. Here are field notes on a hook that detects misses, pinning doc versions, and a harness that checks generated code every time.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →