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
- Started
opencode --auto in foot on Hyprland (18:38).
- Worked in a session, then left the TUI idle (last session write 18:56:40).
- Scaled the external display DP-1 from 3.13 → 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.
- Hyprland + foot, OpenCode TUI running (
opencode --auto is enough; session can be idle).
- External display: Apple Pro Display XDR,
6016x3384@60.
- Scale DP-1 up through 2 → ~3.13 → 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
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
ud2abort 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 localfootsession that had already been running for ~56 minutes, not a partial capability handshake at startup.What happened
opencode --autoin foot on Hyprland (18:38).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.
opencode --autois enough; session can be idle).6016x3384@60.SIGILL.Logical resolution at those scales:
Going 2 → 3.13 did not kill it. The abort is on the step to 4.
Two hits, same abort, same trigger
opencode --autoopencode --autoBoth cores have identical offsets:
That is the same
#0/#5pair reported in #41483.Symbolized OpenTUI frame
libopentui.sois still on disk (/tmp/.9adb5cbffaf2ed8f-00000000.so, not stripped, has DWARF).addr2lineon frame #5: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:
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 /
TIOCSWINSZto foot. OpenTUI then redraws.trySetTransparentTextCellFastindexesself.buffer.char[index]with no bounds check;OptimizedBuffer.resizereallocs those arrays. A draw that still holds an index computed against the pre-resize width/height would trip a Zig safety panic, which becomes thisud2.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
ud2, not EVEX)--autoitself (that is just how the agent is launched; the abort is in the renderer)Environment
libopentui.soextracted to/tmp/.9adb5cbffaf2ed8f-00000000.so7.1.5-arch1-1-ptl, glibc 2.44DP-16016×3384@60Expected
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.dbsurvived; the crash was during an idle redraw.Related
ud2/libopentui+0x1d061d, trigger is a partial capability handshake at startupbufferDrawBoxpanic on grapheme / clip