[BUG] TUI crash: MarkupError in ApprovalDialog when content contains "[tag=value:" pattern
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Summary
ApprovalDialog (Textual) crashes with rich.errors.MarkupError when the content being approved contains text that resembles Rich/Textual markup tags ([name=value] style). The widget appears to render user-supplied content with markup=True instead of escaping [ or passing markup=False.
Environment
- Claude Code:
2.1.126 - OS:
Linux 6.17.0-20-generic(Ubuntu 24.04) - Python:
3.12.3 - textual:
8.2.4 - rich:
15.0.0
Reproduction
Create a file with bracket-prefixed lines that look like markup tags:
print(f"[stage] item count = {n}")
print(f"[stage] other count = {m}")
Trigger any tool call that surfaces this content in the approval dialog
(Read / Edit / a Bash command whose preview includes the text). The dialog crashes during layout in _compositor.reflow.
Expected
Dialog renders the content as plain text — [stage], =, etc. .
Actual
MarkupError: Expected markup value (found '=<token>:\n').
Traceback (relevant frames):
textual/screen.py:1354 in _refresh_layout
→ textual/_compositor.py:387 in reflow
→ textual/_compositor.py:744 in _arrange_root
→ textual/_compositor.py:601 in add_widget
→ textual/screen.py:543 in arrange
→ textual/_arrange.py:97 in arrange
→ textual/layouts/vertical.py:53 in arrange
→ textual/_resolve.py:254 in resolve_box_models
→ textual/widget.py:1838 in _get_box_model
→ textual/widget.py:1939 in get_content_height
→ textual/widget.py:4471 in _render
→ textual/widgets/_static.py:83 in render
→ textual/widgets/_static.py:62 in visual
visualize(self, self.__content, markup=self._render_markup)
^^^^^^^^^^^^^^^^^^^^^
The crashing widget is Static() inside ApprovalDialog → Vertial-from-member, PromptOptionsTable, Static#approval-auto-hint,Static]. _render_markup is True, so any [ in user content is treated as markup.
Suspected fix
In the Static(...) constructions inside ApprovalDialog (and der user-provided text — tool result preview, prompt body, etc.),either:
- Pass
markup=False, or - Pre-escape with
rich.markup.escape(text)before passing to
Either approach renders [tag=value] content literally and avoi
Frequency
Reliably reproducible. Occurs whenever the approval dialog body contains [tag=value]-shaped substrings — common in:
- Python
printstatements with bracketed log prefixes - Markdown notes quoting such code
- Any CLI output reproduced as a code block
In affected projects the crash recurs every few tool calls untile.
What Should Happen?
Expected
Dialog renders the content as plain text — [stage], =, etc. should be displayed verbatim.
Error Messages/Logs
Traceback (relevant frames):
textual/screen.py:1354 in _refresh_layout
→ textual/_compositor.py:387 in reflow
→ textual/_compositor.py:744 in _arrange_root
→ textual/_compositor.py:601 in add_widget
→ textual/screen.py:543 in arrange
→ textual/_arrange.py:97 in arrange
→ textual/layouts/vertical.py:53 in arrange
→ textual/_resolve.py:254 in resolve_box_models
→ textual/widget.py:1838 in _get_box_model
→ textual/widget.py:1939 in get_content_height
→ textual/widget.py:4471 in _render
→ textual/widgets/_static.py:83 in render
→ textual/widgets/_static.py:62 in visual
visualize(self, self.__content, markup=self._render_markup)
^^^^^^^^^^^^^^^^^^^^^
Steps to Reproduce
Suspected fix
In the Static(...) constructions inside ApprovalDialog (and any sibling widgets that render user-provided text — tool result preview, prompt body, etc.), either:
- Pass
markup=False, or - Pre-escape with
rich.markup.escape(text)before passing toStatic.
Either approach renders [tag=value] content literally and avoids the parser path entirely.
Frequency
Reliably reproducible. Occurs whenever the approval dialog body contains [tag=value]-shaped substrings — common in:
- Python
printstatements with bracketed log prefixes - Markdown notes quoting such code
- Any CLI output reproduced as a code block
In affected projects the crash recurs every few tool calls until those files are out of scope.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.126
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗