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
Bashcall likegrep -rorfindwhose 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
/cancelpress 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:
- 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.
- 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.
- 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:
- Press Enter once with no extra input. Occasionally the client will retransmit the orphaned result.
- 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. - 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 3tofind) so you do not reproduce the original blowup. - If the session is truly stuck, open a fresh Claude Code window and paste the
/compactsummary 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.txtIn 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
nohupor insidetmux, thenReadthe 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:
- Try
claude /resumein a new tab to see if the previous session can be reattached - If not, open a fresh session and feed it a pre-written summary like
cat .claude/last_session_summary.md - Add a line to your project's
CLAUDE.mdinstructing Claude to start each recovery by runninggit statusandgit log -3and 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 callThat 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.