opentui

Build terminal UIs with OpenTUI. Covers Core, frameworks, components, application APIs, testing, extensions, integrations, deployment, and public API lookup.

Install
npx skills add 'https://github.com/anomalyco/opentui/tree/main/packages/web/src/content'
Download bundle ↓
main · ac753b4Scanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗

docs/test-and-debug/troubleshooting.mdx

docs/test-and-debug/troubleshooting.mdxBrowse 89 files
View on GitHub
← Back to SKILL.md

title: Troubleshooting description: Identify common runtime, terminal, plugin, integration, and test failures and open the canonical fix skill: entry: true intents: [troubleshooting, terminal-reset, ffi-errors, native-loading, runtime-plugins, protocols, test-timeouts]

Troubleshooting

Start with the visible symptom. Run the diagnostic in its row, then open the linked guide for the complete behavior.

Terminal and output

SymptomDiagnostic and first actionCanonical guide
Keys do not echo after exitOn POSIX, run stty -a. The flags -echo or -icanon show unrestored terminal input state. Run reset, then inspect every exit path. SIGKILL cannot run signal handlers or renderer.destroy().Lifecycle and cleanup
Logs overwrite or corrupt the UIRead renderer.screenMode, renderer.externalOutputMode, and renderer.consoleMode. Also check OTUI_USE_ALTERNATE_SCREEN and OTUI_OVERRIDE_STDOUT. Use the console overlay for console.*, or use split-footer capture for stdout. Stderr remains separate.Renderer output modes and Console overlay
Main-screen or split-footer rows remain damagedConfirm the resolved screenMode. Call destroy() before the transport closes. A custom transport needs time to flush shutdown bytes.Screen modes and custom cleanup

Node.js and native loading

For a native crash, use Native crash debugging to load matching release symbols and collect a useful report.

SymptomDiagnostic and first actionCanonical guide
OpenTUI native FFI is not available for this runtime yetRun node --version. It must print v26.4.0 or later. Start the ESM app with node --experimental-ffi app.mjs. With --permission, also grant --allow-ffi and native-library read access.Node.js runtime
ERR_REQUIRE_ASYNC_MODULEFind require("@opentui/core") or a CommonJS entry. Change the application to ESM and use import.Node.js runtime
A native package or library is missingRun bun -e 'console.log(process.platform, process.arch, process.env.OPENTUI_LIBC ? process.env.OPENTUI_LIBC : "glibc")'. Replace bun with node for a Node.js host. Check for the matching @opentui/core-* optional package. An install that omits optional dependencies can defer the failure until native work.Native artifacts
Linux reports a loader error for libopentui.soCompare the selected libc with the target system. Set OPENTUI_LIBC=musl before Core imports on musl. On Alpine, install libstdc++ and libgcc.Select the Linux libc
OTUI_ASSET_ROOT must be an absolute directoryPrint process.env.OTUI_ASSET_ROOT. Replace a relative value with an absolute path before Core imports.OTUI_ASSET_ROOT
Missing OpenTUI assetCompare the missing key with the exact keys from build-time getNodeAssets(). A configured asset root has no package fallback. Extract or copy the complete asset set.Runtime assets and Node.js SEA

Runtime-loaded modules

SymptomDiagnostic and first actionCanonical guide
A runtime-plugin entry says it is Bun-onlyCheck process.versions.bun. Run the host with Bun. Node.js cannot use these entry points.Runtime module loading
The installer says it is already installed without a specifierSearch the entry graph for a side-effect runtime-plugin support import. Remove it, then call the matching /configure installer once with the complete additional map.Configure before loading
A plugin receives a different Core, React, or Solid singletonCompare one exported object by identity in the host and plugin. Search for stacked Core and framework installers. Keep one host installer and one complete map.Choose one installer
A second installer call does not replace an existing map valueRecord the return values. The first compatible call returns true and later compatible calls return false. Existing keys keep their first installed entries.Repeated installation
A Three.js import fails inside a pluginInspect the plugin's exact import. The first-party map exposes only @opentui/three. It does not expose three, three/webgpu, or three/tsl. Deploy those dependencies or add explicit trusted host mappings.Default module maps
A dependency under node_modules does not use the host runtimeCheck its extension and nearest package.json. Rewriting there supports ESM only. A CommonJS helper that imports runtime modules is not rewritten.Rewriting behavior
Solid TSX under node_modules fails or uses the wrong JSX runtimeCheck whether the package ships uncompiled JSX or TSX. The Solid transform excludes node_modules. Publish precompiled ESM or load source from outside that directory.Solid transform order
A compiled executable cannot find a pluginLog the resolved plugin URL. Check that the plugin file and every unmapped dependency exist outside the executable. Runtime support does not embed unknown sidecars.Executable sidecars and deployment forms

Integrations and protocols

SymptomDiagnostic and first actionCanonical guide
Tree-sitter reports Worker initialization timed out or a generic highlight initialization errorCall await client.initialize() directly to retain the original error. Check the worker, WASM, parser, query, and data paths. Under Node.js permissions, allow workers, asset reads, and data-path writes.Tree-sitter and runtime assets
An image uses Unicode blocks instead of Kitty or SixelLog renderer.capabilities, renderer.resolution, and image.effectiveProtocol. Auto mode uses blocks in tmux. Sixel also uses blocks until pixel resolution is available. Check protocol environment overrides.Image rendering protocol
Image output breaks inside a multiplexerRead renderer.capabilities?.multiplexer. Auto mode chooses blocks in tmux. Explicit Kitty or usable Sixel uses tmux passthrough. Remove unsupported forced protocols.Image rendering protocol and terminal capabilities
An SSH clipboard operation affects the serverRead renderer.capabilities?.remote and the host and terminal result statuses. Host clipboard access targets the SSH server. Use terminal-only for the client clipboard.Remote clipboard sessions
triggerNotification() returns falseRead renderer.isDestroyed, renderer.capabilities?.notifications, and renderer.capabilities?.multiplexer. The method returns false after destruction or without a detected protocol. Check OPENTUI_NOTIFICATIONS and OPENTUI_NOTIFICATION_PROTOCOL.Notifications
Notifications fail through tmux or ZellijIn tmux, enable the required passthrough policy. In Zellij, confirm OSC 99 forwarding support. Use an override only when detection misses supported forwarding.Notification multiplexers
ThreeRenderable init failed appears once and the view stays blankRead the logged WebGPU error and check bun-webgpu 0.1.7. The renderable records an initialization failure and does not retry. Fix the cause, then create a new renderable.ThreeRenderable lifecycle

Test waits

SymptomDiagnostic and first actionCanonical guide
Timed out waiting for visual idle after ... framesRead the attached frameId, nativeFrameCount, cellsUpdated, and scheduler fields. Stop unintended live rendering or release the live request. Increase maxFrames only when the expected work needs more frames.Waiting for observable output

Native builds across worktrees

Zig shares its global cache by default. For repeated native builds across many worktrees, you can also share the project cache:

export ZIG_LOCAL_CACHE_DIR="$HOME/.cache/opentui/zig-local-0.16.0"
bun run build:native

Use a persistent local directory. Use a separate directory for each Zig version. bun run clean does not remove an external cache.

Next

Referenced from SKILL.md