Skip to main content
This guide covers common issues when working with Kraken TUI and how to resolve them.

Build Problems

Native Library Not Found

Symptom:
Error: Unable to load native library
DLOpen error: libkraken_tui.so: cannot open shared object file
Solution:
# Build the native library first
cargo build --manifest-path native/Cargo.toml --release

# Verify the artifact exists
ls native/target/release/libkraken_tui.* 
The native library must be built in release mode for optimal performance.

Rust Toolchain Issues

Symptom:
error: package `kraken_tui v0.1.0` cannot be built because it requires rustc 1.93 or newer
Solution:
# Update Rust toolchain
rustup update stable
rustc --version  # Should be 1.93.x or newer

Missing Dependencies

Symptom:
error: linking with `cc` failed
/usr/bin/ld: cannot find -lxcb
Solution (Linux):
# Debian/Ubuntu
sudo apt-get install libxcb-dev

# Fedora/RHEL
sudo dnf install libxcb-devel
Solution (macOS):
# Usually no additional dependencies needed
# If issues occur, install Xcode Command Line Tools
xcode-select --install

Windows Build Issues

Symptom:
error: linker `link.exe` not found
Solution:
# Install Visual Studio Build Tools with C++ support
# Or use rustup's MSVC toolchain
rustup default stable-x86_64-pc-windows-msvc

Runtime Errors

Context Not Initialized

Symptom:
KrakenError: context not initialized
Cause: Attempting operations before calling Kraken.init() or after shutdown(). Solution:
const app = Kraken.init(); // Must be first

const box = new Box();
app.setRoot(box);

app.render();
app.shutdown(); // Must be last

// Don't use app after shutdown()

Invalid Handle Errors

Symptom:
KrakenError: invalid handle: 42
Cause: Using a widget after it’s been destroyed. Solution:
const box = new Box();
box.destroy();

// DON'T do this:
// box.setStyle({ fg: "red" }); // Error!

// Instead, create a new widget:
const newBox = new Box();
newBox.setStyle({ fg: "red" });

Tree Structure Violations

Symptom:
KrakenError: node 5 already has parent 3
Cause: Attempting to append a widget that’s already in the tree. Solution:
const parent1 = new Box();
const parent2 = new Box();
const child = new Text({ content: "Hello" });

parent1.append(child);

// To move to parent2:
parent1.removeChild(child);
parent2.append(child);

Encoding Errors

Symptom:
KrakenError: invalid UTF-8
Cause: Passing non-UTF-8 bytes to FFI functions. Solution:
// CORRECT: Use TextEncoder
const text = "Hello, 世界";
const utf8 = new TextEncoder().encode(text);
ffi.tui_set_content(handle, ptr(utf8), utf8.byteLength);

// WRONG: Don't pass arbitrary bytes
const invalid = new Uint8Array([0xFF, 0xFE]);
// ffi.tui_set_content(handle, ptr(invalid), 2); // Error!

Performance Issues

High Frame Time

Symptom: Sluggish rendering, >16ms per frame Diagnosis:
app.render();

const layoutUs = ffi.tui_get_perf_counter(0);
const renderUs = ffi.tui_get_perf_counter(1);
const diffCells = ffi.tui_get_perf_counter(2);

console.log(`Layout: ${layoutUs}µs, Render: ${renderUs}µs, Diff: ${diffCells} cells`);

if (layoutUs > 8000) {
  console.warn("Layout is slow - check widget count and nesting depth");
}
Solutions:
// SLOW: 1000 individual Text widgets
for (let i = 0; i < 1000; i++) {
  container.append(new Text({ content: `Item ${i}` }));
}

// FAST: Single Text with concatenated content
const content = Array.from({ length: 1000 }, (_, i) => `Item ${i}`).join("\n");
container.append(new Text({ content }));
// SLOW: Sets dirty flag 3 times
widget.setStyle({ fg: "red" });
widget.setStyle({ bg: "blue" });
widget.setStyle({ bold: true });

// FAST: Single dirty flag
widget.setStyle({
  fg: "red",
  bg: "blue",
  bold: true
});
// For large text content, use ScrollBox to clip rendering
const scrollBox = new ScrollBox({ width: 80, height: 24 });
const largeText = new Text({ content: veryLargeString });
scrollBox.append(largeText);

Event Buffer Buildup

Symptom: Delayed or dropped input events Diagnosis:
const eventDepth = ffi.tui_get_perf_counter(3);
if (eventDepth > 50) {
  console.warn(`Event buffer has ${eventDepth} pending events`);
}
Solution:
// Drain events more frequently
while (running) {
  app.readInput(16); // Read input every frame
  
  // Process ALL events
  for (const event of app.drainEvents()) {
    handleEvent(event);
  }
  
  app.render();
}

Memory Leaks

Symptom: Growing memory usage, increasing node count Diagnosis:
const nodeCount = ffi.tui_get_node_count();
console.log(`Active widgets: ${nodeCount}`);
Solutions:
// WRONG: Orphans children
parent.destroy();

// CORRECT: Recursively destroys entire subtree
parent.destroySubtree();
const animHandle = widget.animate({
  property: "opacity",
  target: 0,
  duration: 500
});

// Later, before destroying widget:
widget.cancelAnimation(animHandle);
widget.destroy();
const theme = new Theme();
theme.setColor(ThemeKey.FG, 0xFF00FF00);
app.applyTheme(rootWidget, theme);

// Later:
app.clearTheme(rootWidget);
theme.destroy();

Terminal Issues

Colors Not Displaying

Symptom: Colors appear as gray or monochrome Diagnosis:
const caps = ffi.tui_get_capabilities();
if ((caps & 0x01) === 0) {
  console.log("Terminal lacks truecolor support");
}
Solutions:
  • Set COLORTERM=truecolor environment variable
  • Use a modern terminal emulator (iTerm2, Alacritty, Windows Terminal)
  • Colors automatically degrade: truecolor → 256-color → 16-color → monochrome

Mouse Events Not Working

Symptom: Click events not firing Diagnosis:
const caps = ffi.tui_get_capabilities();
if ((caps & 0x02) === 0) {
  console.log("Terminal lacks mouse support");
}
Solutions:
  • Enable mouse reporting in terminal settings
  • Test with known-good terminal (Alacritty, Windows Terminal)
  • Keyboard focus traversal remains operational

Terminal Size Detection

Symptom: Layout doesn’t fit terminal Solution:
const width = new Uint16Array(1);
const height = new Uint16Array(1);
ffi.tui_get_terminal_size(ptr(width), ptr(height));
console.log(`Terminal: ${width[0]} cols × ${height[0]} rows`);

Terminal Not Restored on Exit

Symptom: Terminal remains in raw mode after crash Solution:
process.on("SIGINT", () => {
  try {
    app.shutdown(); // Restore terminal
  } catch (error) {
    console.error("Shutdown failed:", error);
  }
  process.exit(0);
});

process.on("uncaughtException", (error) => {
  console.error("Fatal error:", error);
  try {
    app.shutdown();
  } catch {}
  process.exit(1);
});

Debugging Workflow

Step 1: Enable Debug Mode

const app = Kraken.init();
ffi.tui_set_debug(1);

// Now stderr will show:
// - Tree mutations (append, remove, destroy)
// - Layout recomputations
// - Dirty flag propagation
// - Event buffer state
// - Hit-test traces

Step 2: Check Performance Counters

function logDiagnostics(): void {
  console.error("=== Diagnostics ===");
  console.error(`Layout: ${ffi.tui_get_perf_counter(0)}µs`);
  console.error(`Render: ${ffi.tui_get_perf_counter(1)}µs`);
  console.error(`Diff cells: ${ffi.tui_get_perf_counter(2)}`);
  console.error(`Event buffer: ${ffi.tui_get_perf_counter(3)}`);
  console.error(`Total nodes: ${ffi.tui_get_perf_counter(4)}`);
  console.error(`Dirty nodes: ${ffi.tui_get_perf_counter(5)}`);
  console.error(`Active animations: ${ffi.tui_get_perf_counter(6)}`);
}

Step 3: Validate State

function validateWidget(widget: Widget): boolean {
  if (widget.handle === 0) {
    console.error("Invalid handle: widget was destroyed");
    return false;
  }

  const nodeCount = ffi.tui_get_node_count();
  if (nodeCount === 0) {
    console.error("No nodes exist - context may be uninitialized");
    return false;
  }

  return true;
}

Step 4: Isolate the Issue

// Minimal reproduction
const app = Kraken.init();
ffi.tui_set_debug(1);

const box = new Box({ width: "100%", height: "100%" });
app.setRoot(box);

console.log("Before render");
app.render();
console.log("After render");

app.shutdown();

Getting Help

If you encounter an issue not covered here:
  1. Check error message: Kraken errors include detailed context
  2. Enable debug mode: ffi.tui_set_debug(1)
  3. Review diagnostics: Use performance counters
  4. Create minimal reproduction: Isolate the issue
  5. Report the issue: Include version, platform, and code sample
See the GitHub repository for issue reporting and community support.

Build docs developers (and LLMs) love