Tool results with non-text content blocks render as "(eval omitted)" after context compaction (v2.0.74)
Summary
After a context/token-limit compaction event, tool results (Bash, Read, Edit, etc.) start rendering to the model as the literal string (eval omitted) instead of the real output. The commands themselves execute successfully and the real stdout is correctly persisted in the session transcript's toolUseResult — only the rendered-back-to-the-model text is replaced. One occurrence rendered as (eval omitted)</object>, with the closing tag wrong (</object> instead of </output>).
This silently blinds the assistant to all tool output, forcing every command to be re-run via subagents to recover their results.
Environment
- Claude Code version: 2.0.74
- Install path:
~/.claude/local/node_modules/@anthropic-ai/claude-code/ - Platform: macOS (darwin 25.5.0)
Root cause (located in sdk.mjs)
The tool_result rendering only handles type === "text" content blocks and falls back to a hardcoded (eval omitted) for anything else:
case "tool_result": {
let Q = typeof B.content == "string"
? B.content
: B.content?.map((I) => I.type === "text" ? I.text : "(eval omitted)").join("");
return `<tool_use_result>${G}<output>${Q}</output></tool_use_result>`
}
A separate path builds XML using the block's type field as the tag name, which is how the mismatched </object> appears:
B.map((I) => `<${I.type}>${I.type === "text" ? I.text : JSON.stringify(I)}</${I.type}>`)
So when a content block's type is something other than text (e.g. object), it is either replaced by (eval omitted) or wrapped in <object>…</object>, producing the corrupted <output>…(eval omitted)</object> we observed.
Trigger / Repro
The breakage begins right after a Output token limit hit. Resume directly compaction event in a long session. The working hypothesis is that context rebuild re-wraps some tool-result content blocks into a non-text type (e.g. a cache/placeholder or {type:"object",...}), which then hits the (eval omitted) fallback on every subsequent render.
Observed in this order within one session:
- Early tool calls (gh, git show, git fetch) render normally.
- A token-limit compaction occurs.
- From then on, every Bash/Read/Edit result renders as
(eval omitted)(real output intact in transcript'stoolUseResult).
Impact
- The model loses visibility into all tool output mid-session, with no error surfaced (it is not a thrown error, just silently wrong rendered text).
- Hard to notice: writes/edits succeed, so only output-reading is affected.
- Workaround today is to route everything through subagents (their rendering is unaffected), which is expensive.
Suggested fix
In the tool_result content mapping, handle non-text block types explicitly (e.g. image → placeholder describing the image; serialize unknown/object blocks to readable JSON) instead of the opaque (eval omitted) fallback, and stop deriving XML tag names directly from block.type (use a fixed <output> wrapper) so a stray type can't corrupt the tag structure. Most importantly, investigate why post-compaction tool-result blocks lose their text type.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗