anomalyco / anomalyco/opencode

TUI SIGILL (ud2) in OpenTUI drawTextBuffer when compositor scale jumps to 4

Open
#42,094 6 comments 2 reactions 1 assignee View on GitHub

@kommander is already working on this.

Since Aug 12, 2026.

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

Description

Summary

An idle OpenCode TUI aborts with SIGILL (ud2) the instant the compositor scales the monitor up to 4. This has happened twice, weeks apart, on two OpenCode versions, at the same instruction pointer and on the same second as the scale-to-4 event.

This is not a missing-CPU-feature SIGILL. The faulting instruction is a deliberate ud2 abort in the bundled Bun runtime, reached from OpenTUI's text-buffer draw path.

Same abort site as #41483 (opencode+0x2407064 / libopentui.so+0x1d061d), but a different trigger: a healthy local foot session that had already been running for ~56 minutes, not a partial capability handshake at startup.

What happened

  1. Started opencode --auto in foot on Hyprland (18:38).
  2. Worked in a session, then left the TUI idle (last session write 18:56:40).
  3. Scaled the external display DP-1 from 3.13 → 4.
  4. Kernel recorded the abort on that same second:
Aug 12 19:34:41 traps: opencode[3769384] trap invalid opcode ip:2607064

The process dumped core (si_code: ILL_ILLOPN). No OOM, 37 GiB free.

Reproduction

Reliable on this machine whenever OpenCode's TUI is open and the monitor is scaled to 4.

  1. Hyprland + foot, OpenCode TUI running (opencode --auto is enough; session can be idle).
  2. External display: Apple Pro Display XDR, 6016x3384@60.
  3. Scale DP-1 up through 2 → ~3.13 → 4.
  4. OpenCode dies immediately with SIGILL.

Logical resolution at those scales:

scale logical size
2 3008×1692
3.13 1920×1080
4 1504×846

Going 2 → 3.13 did not kill it. The abort is on the step to 4.

Two hits, same abort, same trigger

when version command scale event (same second)
2026-08-04 19:27:23 CEST 1.18.11 opencode --auto DP-1 3.20 → 4
2026-08-12 19:34:41 CEST 1.18.16 opencode --auto DP-1 3.13 → 4

Both cores have identical offsets:

#0  opencode + 0x2407064     ; ud2
#1  opencode + 0x2405266
#2  opencode + 0x32dd8bf     ; napi_internal_suppress_crash_on_abort_if_desired
#3  opencode + 0x44e35ad
#4  libc.so.6 + 0x3e6f0      ; __restore_rt
#5  libopentui.so + 0x1d061d

That is the same #0/#5 pair reported in #41483.

Symbolized OpenTUI frame

libopentui.so is still on disk (/tmp/.9adb5cbffaf2ed8f-00000000.so, not stripped, has DWARF). addr2line on frame #5:

buffer.OptimizedBuffer.trySetTransparentTextCellFast
  packages/core/src/zig/buffer.zig:896

called from:
  OptimizedBuffer.drawTextBufferInternal   buffer.zig:1659
  OptimizedBuffer.drawTextBuffer           buffer.zig:1274
  lib.bufferDrawTextBufferView             lib.zig:2521

The instruction at that offset is a cell-buffer load inside the fast path (cmpl $0xff, (%rsi,%rcx,4)), not a SIMD op.

Faulting bytes in the main binary:

260705f:  call   0x2634e80     ; noreturn abort helper
2607064:  ud2                  ; <- RIP
2607066:  int3 int3 int3 ...

Classic Zig/Bun "noreturn returned" / panic abort, which the kernel reports as trap invalid opcode.

Inference (not proven)

Scale 3.13 → 4 shrinks the logical viewport by ~22% and delivers a SIGWINCH / TIOCSWINSZ to foot. OpenTUI then redraws. trySetTransparentTextCellFast indexes self.buffer.char[index] with no bounds check; OptimizedBuffer.resize reallocs those arrays. A draw that still holds an index computed against the pre-resize width/height would trip a Zig safety panic, which becomes this ud2.

I have not single-stepped the panic reason (no panic string in the journal). The timestamp match + the symbolized draw path is the evidence.

Ruled out

  • OOM / resource exhaustion
  • AVX / "baseline binary on old CPU" (Intel Core Ultra X7 358H, avx2+; the opcode is ud2, not EVEX)
  • A crash in the herdr OpenCode plugin — it is installed, but it is not on the crashing stack
  • --auto itself (that is just how the agent is launched; the abort is in the renderer)

Environment

  • opencode 1.18.16 (previous hit: 1.18.11), installed via mise
  • Bun v1.3.14 (Linux x64 baseline), bundled
  • OpenTUI native libopentui.so extracted to /tmp/.9adb5cbffaf2ed8f-00000000.so
  • OS Arch Linux, kernel 7.1.5-arch1-1-ptl, glibc 2.44
  • compositor Hyprland 0.56.2
  • terminal foot 1.27.0, JetBrainsMono Nerd Font 9
  • display Apple Pro Display XDR DP-1 6016×3384@60
  • CPU Intel Core Ultra X7 358H

Expected

A compositor scale change (or any SIGWINCH / resize) should reflow the TUI. It should not abort the process.

Workaround

Do not scale the monitor to 4 while OpenCode is open, or close OpenCode first. Session data in ~/.local/share/opencode/opencode.db survived; the crash was during an idle redraw.

Related

  • #41483 — identical ud2 / libopentui+0x1d061d, trigger is a partial capability handshake at startup
  • #38199 — TUI crash on extreme shrink (~2×1); Bun segfault, different stack
  • anomalyco/opentui#971 — OpenTUI bufferDrawBox panic on grapheme / clip

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.