This repository was archived by the owner on Jun 1, 2026. It is now read-only.
fix(tui): stop session-switch crash from object-valued tool fields in <text>#27
Merged
Merged
Conversation
… <text>
The TUI crashed with a fatal "TextNodeRenderable only accepts strings,
TextNodeRenderable instances, or StyledText instances" when switching into
a session whose parts contained tool input/metadata or diagnostic/error
fields that were not strings.
Root cause: `packages/codeplane/src/tui/routes/session/index.tsx` interpolated
several `unknown`/`any`-typed values (tool `state.input.{command,pattern,url,
query,name}`, `diagnostic.message`, and `message.error.data.message`) directly
as children of opentui `<text>` elements. Those fields can hold partially
streamed or model-supplied objects/arrays. On session switch, `syncSessionData`
in `context/sync.tsx` reloads all messages/parts and SolidJS re-renders them; an
object child reaches opentui's `TextNodeRenderable.add()`, which only accepts
strings/StyledText and throws, taking down the whole TUI. It reproduced with and
without a PDF attachment because the trigger is the tool/diagnostic render path,
not attachments.
Fix: add `textValue()` (new `src/tui/util/text-value.ts`) that always returns a
string — passing strings through, rendering nullish as "", coercing scalars, and
JSON-serializing objects/arrays with a defensive fallback — and wrap every
at-risk `<text>` interpolation with it. This mirrors the existing guards in
`feature-plugins/system/session-v2.tsx` and `routes/session/permission.tsx`.
Verification:
- bun --cwd packages/codeplane test test/tui/text-value.test.ts (5 pass)
- bun turbo typecheck --filter=codeplane (0 errors)
- bun lint (0 errors)
Co-Authored-By: codeplane-agent[bot] <287208015+codeplane-agent[bot]@users.noreply.github.com>
The previous commit added the textValue call sites and the helper module but did not import it in routes/session/index.tsx, which broke typecheck (TS2304: Cannot find name 'textValue'). Add the missing import and restore the InlineTool child indentation. Verification: - bun turbo typecheck --filter=codeplane (0 errors) - bun --cwd packages/codeplane test test/tui/text-value.test.ts (5 pass) Co-Authored-By: codeplane-agent[bot] <287208015+codeplane-agent[bot]@users.noreply.github.com>
617cecf to
5d0023c
Compare
Collaborator
Author
Review NotesVerdict: APPROVED — ready to merge What this doesFixes a TUI crash where switching into a session with non-string tool input/metadata fields (objects, arrays, etc.) would throw in Review
No issues foundThis is a low-risk bugfix with good test coverage. Safe to merge. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #26. The TUI crashed with a fatal
TextNodeRenderable only accepts strings, TextNodeRenderable instances, or StyledText instanceswhen switching into a session whose parts contained tool input/metadata, diagnostic, or error fields that were not strings. It reproduced with and without a PDF attachment, because the trigger is the tool/diagnostic render path, not attachments.Cause / Investigation
@opentui/core)TextRenderable.add()accepts onlystring,TextNodeRenderable, orStyledText. Any other child (plain object, array, store proxy,Date, etc.) throws the reported error. In the@opentui/solidreconciler,insertExpression's finalelsebranch passes such values straight toparent.add().packages/codeplane/src/tui/routes/session/index.tsxinterpolated severalunknown/any-typed values directly as<text>children:state.input.{command,pattern,url,query,name}(typedunknown; raw/partial/streamed tool-call JSON can be an object/array, not a string)diagnostic.message(Record<string, any>)message.error.data.message(unknownforMessageOutputLengthError)syncSessionDataincontext/sync.tsxreloads all messages/parts viareconcile, and SolidJS re-renders them. An object child then reachesTextNodeRenderable.add()and takes down the whole TUI.feature-plugins/system/session-v2.tsx(stringValue()) androutes/session/permission.tsx(typeof === "string"guards) already guard these exact fields; the liveroutes/session/index.tsxdid not. That asymmetry was the bug.Changes
packages/codeplane/src/tui/util/text-value.ts(new):textValue()always returns a string — passes strings through, renders nullish as"", coerces scalars (number/bigint/boolean), and JSON-serializes objects/arrays with a defensive fallback that never throws.packages/codeplane/src/tui/routes/session/index.tsx: wrap every at-risk<text>interpolation withtextValue(...)— Shellcommand(block + inline), Glob/Greppattern, WebFetchurl, WebSearchquery, Skillname,Diagnosticsmessage, and the assistant errordata.message.packages/codeplane/test/tui/text-value.test.ts(new): regression coverage assertingtextValuealways returns a string for strings, nullish, scalars, objects/arrays (the crash case), and hostile inputs (circular refs, symbols, throwingtoJSON).Verification
bun --cwd packages/codeplane test test/tui/text-value.test.ts— 5 pass, 0 failbun turbo typecheck --filter=codeplane— 0 errorsbun lint— 0 errors (warnings only)Note:
test/tui/dispatch*.test.tsandauth-helper.test.tsfail in this environment both with and without this change (pre-existing global-state flakes per AGENTS.md); they are unrelated to this fix.