anomalyco / anomalyco/opencode

tui: slot render returning plain string crashes with "Orphan text error"; @opentui/* unimportable in plugins

Open
#42,338 1 comment 0 reactions 1 assignee View on GitHub

@kommander is already working on this.

Since Aug 13, 2026.

2.0
Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Summary

TUI crashes with Orphan text error: "<string>" must have a <text> as a parent when a TUI plugin slot (sidebar.content) returns a plain string from render(). Plugins are effectively forced to return plain strings because importing @opentui/* inside a TUI plugin fails on next-17403 with OPENTUI_FORCE_WCWIDTH already registered with different configuration (host bug).

Environment

  • opencode version: 0.0.0-next-17403 (next channel)
  • OS: Linux 5.15.0-1081-oracle #87~20.04.1-Ubuntu SMP Mon Apr 28 12:53:11 UTC 2025 (aarch64 / arm64)
  • Terminal: VS Code 1.133.0 (TERM=xterm-256color, truecolor)
  • Shell: /bin/bash
  • Install/channel: next (via ~/.opencode/bin/opencode2)
  • Active plugins: usage-tracker.js (server), usage-tracker-tui.js (local TUI plugin at ~/.config/opencode/tui/usage-tracker-tui.js)

Reproduction

  1. Register a TUI plugin claiming the sidebar slot whose render returns a plain string:
import { Plugin } from "@opencode-ai/plugin/tui";

export default Plugin.define({
  id: "plain-string-slot",
  setup: (ctx) => {
    const claim = ctx.ui.slot({
      append: "sidebar.content",
      render: () => "Usage\nin 545.3k  out 125.8k\nre 129.7k  cache 139.8M/0\nhit 100%  cost $0.2697\ntotal 140.6M  steps 68",
    });
    return () => claim();
  },
});
  1. Open the TUI, navigate to a session view with the sidebar rendered.
  2. TUI crashes: Orphan text error: "Usage\nin 545.3k ..." must have a <text> as a parent: box-318 above text-node-554.

Expected Behavior

Either of:

  • A plain string returned from a slot render() is wrapped in a <text> node by the host (so strings are a valid slot payload), or
  • @opentui/* is importable from TUI plugin code so plugins can return proper element trees.

Neither path should crash the TUI. The crash takes down the whole terminal UI, not just the slot.

Actual Behavior

Full TUI crash with the orphan-text error. Stack trace:

Error: Orphan text error: "Usage
in 545.3k  out 125.8k
re 129.7k  cache 139.8M/0
hit 100%  cost $0.2697
total 140.6M  steps 68" must have a <text> as a parent: box-318 above text-node-554
    at w$ (../../node_modules/.bun/@opentui+solid@0.5.2+b9027845aeff97b0/node_modules/@opentui/solid/index.bun.js:559:17)
    at N (../../node_modules/.bun/@opentui+solid@0.5.2+b9027845aeff97b0/node_modules/@opentui/solid/index.bun.js:442:7)
    at P (../../node_modules/.bun/@opentui+solid@0.5.2+b9027845aeff97b0/node_modules/@opentui/solid/index.bun.js:311:13)
    ...
    at children (../tui/src/routes/session/sidebar.tsx:66:7)
    ...
    at children (../tui/src/routes/session/index.tsx:1143:22)

Additional Context

  • The offending plugin was written to return a plain string only because importing @opentui/* in a TUI plugin dies with OPENTUI_FORCE_WCWIDTH already registered with different configuration — so on next-17403 there is no working way to render styled TUI content from a plugin slot.
  • Crash is deterministic: every render of the slot once the plugin has data. Sidebar is unrecoverable while the plugin is active.
  • The session being viewed at crash time had 68 steps; the sidebar showed live usage stats (input/output/reasoning/cache/cost).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.