[Bug] Tool input renderer surfaces "Unhandled node type: string" in permission prompt

Resolved 💬 3 comments Opened Apr 17, 2026 by jizhi0v0 Closed Apr 21, 2026

Bug Description
Unhandled node type: string fallback prompt when rendering complex tool input

Environment

  • Claude Code CLI (latest at time of report, 2026-04-17)
  • Model: Claude Opus 4.7 (1M context), id claude-opus-4-7
  • Platform: macOS 26, Darwin 25.4.0, zsh

Symptom
When Claude invokes a tool whose input contains a sufficiently complex shell string (multi-line bash one-liner with nested quoting, jq filters, while
... do ... done loops, etc.), the tool-use preview in the terminal renders as:

Monitor(GitHub release workflow status for v0.3.141)
prev_main="";prev_tag="";while true;do out=$(gh run list ... )
GitHub release workflow status for v0.3.141

Unhandled node type: string

Do you want to proceed?
❯ 1. Yes

  1. No

Instead of the normal permission-prompt UI (which would say e.g. "Claude wants to use Monitor" with a visible diff/summary of the arguments), the
user gets a generic Do you want to proceed? prompt and the cryptic Unhandled node type: string line inserted into the preview.

Expected

  • Either a properly rendered tool preview with argument highlighting
  • Or the standard permission prompt with a clean description — not a generic proceed/cancel bound to an internal renderer error

Reproduction (best effort)
Invoke a tool (e.g. Monitor or Bash) with a command argument similar to:

prev_main="";prev_tag="";while true;do out=$(gh run list --limit 5 --json databaseId,event,headBranch,status,conclusion,displayTitle 2>/dev/null ||
echo "[]");main=$(echo "$out"|jq -r '[.[]|select(.headBranch=="main" and (.displayTitle|contains("v0.3.141")))][0]|"\(.status) \(.conclusion)
\(.databaseId)"');...done

The preview renderer appears to fail on this input — likely because the AST/markdown node tree for the pretty-printer hits a string node without a
registered handler, and falls back to a generic confirmation dialog.

Impact

  • User cannot see a readable diff of what the tool will run — only the raw command string plus an error line
  • Unhandled node type: string is an internal developer message that shouldn't be surfaced to end users
  • The generic Do you want to proceed? can be confused with the normal permission prompt, which is a safety-critical UI

Guess at root cause
Something in the tool-input renderer — probably the syntax-highlighted bash/diff view — has a switch over AST node types that doesn't cover the
string literal case, so it throws/returns a fallback marker that gets mixed into the prompt.

Suggested fix

  • Add a default handler for string (and any other missing) AST node types that just prints the value verbatim
  • Ensure renderer errors are logged internally, not shown inline with the permission prompt

Environment Info

  • Platform: darwin
  • Terminal: zed
  • Version: 2.1.112
  • Feedback ID: 27cdcd97-eb02-415a-a1ae-ad4d34c644ef

Errors

[{"error":"Error: NON-FATAL: Lock acquisition failed for /Users/bobby/.local/share/claude/versions/2.1.112 (expected in multi-process scenarios)\n    at Od_ (/$bunfs/root/src/entrypoints/cli.js:2748:2177)\n    at Ke6 (/$bunfs/root/src/entrypoints/cli.js:2748:1257)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-17T14:42:58.798Z"},{"error":"AxiosError: timeout of 5000ms exceeded\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:115:13335)\n    at emit (node:events:92:22)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:114:3321)\n    at request (/$bunfs/root/src/entrypoints/cli.js:117:2467)\n    at async QC6 (/$bunfs/root/src/entrypoints/cli.js:439:4055)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-17T14:43:18.818Z"},{"error":"Error: Request was aborted.\n    at makeRequest (/$bunfs/root/src/entrypoints/cli.js:50:3448)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-17T14:43:41.701Z"},{"error":"Error: Request was aborted.\n    at makeRequest (/$bunfs/root/src/entrypoints/cli.js:50:3448)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-17T14:43:50.502Z"},{"error":"AxiosError: timeout of 5000ms exceeded\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:115:13335)\n    at emit (node:events:92:22)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:114:3321)\n    at request (/$bunfs/root/src/entrypoints/cli.js:117:2467)\n    at async QC6 (/$bunfs/root/src/entrypoints/cli.js:439:4055)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-17T14:44:01.703Z"},{"error":"AxiosError: timeout of 5000ms exceeded\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:115:13335)\n    at emit (node:events:92:22)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:114:3321)\n    at request (/$bunfs/root/src/…

Note: Content was truncated.

View original on GitHub ↗

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