Skip to content

tui: V2 plugin JSX crashes with No renderer found #37836

Description

@heditwo

Summary

External V2 TUI plugins load and run setup(), but rendering Solid JSX from a registered slot consistently crashes with No renderer found.

The V2 loader imports external modules directly without first initializing OpenTUI runtime plugin support. Calling ensureRuntimePluginSupport() before those imports makes the same plugin render correctly.

Environment

  • opencode version: opencode2 v0.0.0-next-15543; reproduced with a source build at commit fe0c74f4df2ce751ab8ac511ed6e784ea4bcf179
  • OS: Arch Linux, kernel 7.0.10-arch1-1, x86_64
  • Terminal: Kitty 0.46.2 (TERM=xterm-kitty, COLORTERM=truecolor)
  • Shell: /usr/bin/bash
  • Install/channel: V2 next / source build; packages/tui version 1.18.3; @opentui/solid@0.4.5
  • Active plugins: local anthropic-oauth, anthropic-quota, and the minimal renderer-repro TUI plugin

Reproduction

  1. Build V2 from commit fe0c74f4df2ce751ab8ac511ed6e784ea4bcf179.

  2. Configure this module as an external V2 TUI plugin:

    /** @jsxImportSource @opentui/solid */
    
    export default {
      id: "renderer-repro",
      setup(context) {
        return context.ui.slot("sidebar.content", () => (
          <text>External plugin rendered</text>
        ))
      },
    }
  3. Start the V2 TUI and allow the sidebar.content slot to render.

  4. Observe that setup() completes and the slot is registered, but invoking its JSX renderer crashes.

Expected Behavior

The sidebar displays External plugin rendered.

Actual Behavior

The TUI crashes when the slot renders:

No renderer found

The V2 loader directly imports the external entrypoint:

async function loadPlugin(spec: string, directory: string, packages: PackageResolver) {
const local = spec.startsWith("file://")
? new URL(spec)
: spec.startsWith("./") || spec.startsWith("../") || path.isAbsolute(spec)
? pathToFileURL(path.resolve(directory, spec))
: undefined
const entrypoint = local ? await resolveLocal(local) : await packages.resolve(spec)
if (!entrypoint) return
const mod: { readonly default?: unknown } = await import(entrypoint)
if (!isPlugin(mod.default)) throw new Error(`Invalid V2 TUI plugin module: ${spec}`)
return mod.default

It does not initialize OpenTUI runtime plugin support first, so plugin JSX uses a separate renderer context.

Additional Context

Patched and unpatched binaries were built from the same commit. Adding the following before external plugins are imported fixes the crash and renders the component:

import { ensureRuntimePluginSupport } from "@opentui/solid/runtime-plugin-support/configure"

ensureRuntimePluginSupport()

The default branch already performs equivalent initialization in its TUI plugin runtime:

https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/plugin/tui/runtime.ts#L1-L47

Related issues #36505 and #36525 concern older V2 builds where external plugins were never loaded. This is a later, distinct failure: the plugin is imported, setup() runs, and only Solid JSX rendering fails.

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions