Skip to content

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

Closed as not planned

Description

@dhh

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

Activity

  1. devgtv commented on Aug 14, 2026

    @devgtv

    Third machine reporting in — same abort site, but a different trigger, and confirmation that the latest release still carries the bug.

    Hits on this machine (identical offsets to the ones above):

    when version install command
    2026-08-11 08:19 -03 npx build (opencode-ai, version unknown) npx opencode
    2026-08-14 07:27 -03 1.18.18 mise opencode --auto

    Both SIGILL / ILL_ILLOPN, both with the same #0 opencode+0x2407064 (ud2) and #5 libopentui.so+0x1d061d pair. Verified frame #5 on the Aug 14 core against the extracted .so still on disk (has DWARF): bufferDrawTextBufferView + 4237, and the instruction at that offset is the same cell-buffer load (cmpl $0xff,(%rsi,%rcx,4)).

    Different trigger: no compositor scale event involved. Both crashes happened with the TUI running inside tmux 3.7b (client terminal: foot 1.27.0) on Hyprland 0.56.2, Arch kernel 7.1.8-arch1-3. The Aug 14 crash came ~1 minute after opencode --auto launched, shortly after a fresh boot; nothing display-related in the journal at that second. So a tmux pane/window resize or the startup geometry negotiation appears sufficient to reach the same unclipped-glyph path — making this closer to #41483's startup trigger than to the scale-to-4 one.

    Fix timing note: 1.18.18 was released Aug 13 ~01:15 UTC, before opentui#1361 merged later that morning, so the current latest opencode release still contains the bug.

    Ruled out locally: OOM (3.4 GiB free, nothing in the journal), CPU-feature SIGILL (baseline Bun build; faulting opcode is ud2).

    Filed by Kimi K3 via OpenCode.

  2. simonklee commented on Aug 14, 2026

    @simonklee
    Member

    A fix for this is in v2 branch that we're working on getting out shortly. That means there will not be a 1.18.x patch release for this issue unless v2 keeps on dragging out. I'll check in early next week to see if where we are and consider it again.

  3. confilip commented on Aug 27, 2026

    @confilip

    Third machine, identical abort site, still present on the current release.

    hit version install command
    2026-08-27 22:10:41 CEST 1.18.21 mise opencode

    Same #0 opencode+0x2407064 (ud2) / #5 libopentui.so+0x1d061d pair, verified against the DWARF in the still-on-disk /tmp/.9adf6cbde2f3fdbf-00000000.so: OptimizedBuffer.trySetTransparentTextCellFast at packages/core/src/zig/buffer.zig:896.

    Environment: AMD Ryzen 7 4800HS (Zen 2), Arch (Omarchy), Hyprland, plain interactive opencode with no arguments. Trigger not isolated — no compositor scale event and no tmux in the journal; crashed during an idle redraw after some terminal/window churn. No OOM.

    Corroborates that the bug is still in the latest release and that --auto is not required to reach the unclipped-glyph path.

    Filed by deepseek-v4-flash via opencode.

  4. getaaron commented on Aug 28, 2026

    @getaaron

    I opened this issue which is similar but just happens when the tiles are really small (no scaling/resizing event afaik): #45802 - just linking in case they end up being dupes.

    Similarities:

    Both crashes share the exact same abort site:

    #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
    

    Same bun version (1.3.14)

    Same general setup (opentui native lib, foot terminal, hyprland compositor etc) - probably same version of omarchy (just a suspicion)

  5. zdehasek commented on Aug 31, 2026

    @zdehasek

    Another confirmed occurrence with the identical abort site on a different AMD machine.

    when version install command
    2026-08-31 15:52:12 CEST 1.18.21 ~/.opencode/bin/opencode opencode

    The systemd core has the same frame pair reported here:

    #0  opencode + 0x2407064       ; ud2
    #1  opencode + 0x2405266
    #2  opencode + 0x32dd8bf
    #3  opencode + 0x44e35ad
    #4  libc.so.6 + 0x3e6f0       ; signal trampoline
    #5  libopentui.so + 0x1d061d  ; bufferDrawTextBufferView+4237
    

    Disassembly of frame #5 from the core:

    lib.bufferDrawTextBufferView+4221: mov 0xf0(%rsi),%ecx
    lib.bufferDrawTextBufferView+4227: imul %edx,%ecx
    lib.bufferDrawTextBufferView+4230: add %r10d,%ecx
    lib.bufferDrawTextBufferView+4233: mov 0x30(%rsi),%rsi
    lib.bufferDrawTextBufferView+4237: cmpl $0xff,(%rsi,%rcx,4)

    The final SIGILL is again Bun deliberately executing ud2 after the native renderer memory fault, not an unsupported CPU opcode.

    Trigger was not isolated to a compositor scale change. The OpenCode log for the crashing process shows its last operation as scheduled cleanup prune=7.days nine seconds earlier; there was no terminal resize or display-scale event in the journal around the crash. It was running in a Hyprland graphical terminal scope. No OOM or hardware error occurred.

    Environment:

    • AMD Ryzen 5 7640U with Radeon 760M
    • Arch Linux / Omarchy, kernel 6.18.46-1-lts
    • OpenCode binary build ID c30f169b1bef81fa57467cd091ba53aab5235468
    • 29 threads in the core; OpenTUI and fff native libraries loaded

    coredumpctl list opencode also contains three older OpenCode SIGILL records on this machine (Jan 20, Feb 25, and Jun 25), but those cores are no longer available, so I cannot confirm that they had the same native frame.

    No user data loss was observed; the session database and snapshots survived.

  6. confilip commented on Sep 5, 2026

    @confilip

    Follow-up to my Aug 27 comment — two more hits today, with a much tighter correlation than my earlier report: both crashed instances were spawned by herdr.

    hit version install command context
    2026-09-05 14:57:21 CEST 1.18.21 mise opencode spawned by herdr (pane 6)
    2026-09-05 14:57:56 CEST 1.18.21 mise opencode spawned by herdr (pane 2)

    herdr correlation, from herdr's own server log (~/.config/herdr/herdr-server.log, timestamps UTC):

    12:57:16.317Z herdr::pane: agent changed pane=6 previous_agent=None agent=Some(OpenCode) process=opencode pgid=Some(305681)
    12:57:51.626Z herdr::pane: agent changed pane=2 previous_agent=None agent=Some(OpenCode) process=opencode pgid=Some(309243)
    

    The pgids match the two crashed PIDs exactly. Kernel trap lines show both died at the same instruction pointer as this issue's abort site:

    Sep 05 14:57:21 zephyrus kernel: traps: opencode[305681] trap invalid opcode ip:2607064 error:0 in opencode[21a3064,24c8000+36e6000]
    Sep 05 14:57:56 zephyrus kernel: traps: opencode[309243] trap invalid opcode ip:2607064 error:0 in opencode[21a3064,24c8000+36e6000]
    

    i.e. both processes died ~4.4–4.7 s after herdr logged the agent detection. Both cores have the identical frame pair reported here (#0 opencode+0x2407064 / #5 libopentui.so+0x1d061d). I additionally disassembled frame #5 in today's still-on-disk extracted OpenTUI native lib (/tmp/<hash>-00000000.so, offset 0x1d061d): it lands inside bufferDrawTextBufferView, consistent with the verification in the OP and other comments.

    Reproduction observation (not measured, machine owner's observation): opencode 1.18.21 started directly in foot runs normally; under herdr 0.8.0.r13-1 (Arch package) it has now died at this site twice today. Reliable but not universal: a later herdr-spawned instance (15:03 CEST) is still running without crashing.

    One factual observation from the herdr log, with no causal claim: 4 s before the second spawn, herdr logged a client resize with cell_width_px=0 cell_height_px=0.

    Environment unchanged from my Aug 27 comment (Ryzen 7 4800HS, Arch/Omarchy, Hyprland, foot).

  7. windsorroyalapps commented on Sep 22, 2026

    @windsorroyalapps

    Additional data on this same crash from the 1.18.31 builds (2026-09-19 onward): it is a regression in 1.18.31 and the SIGILL is deterministic at one absolute instruction address across independent processes.

    Verified against the shipped opencode 1.18.31 binary (ET_EXEC, non-PIE, base 0x200000):

    • opencode[7722]: ILL_ILLOPN (ud2) at ip:2607064
    • Worker[65104] (second, unrelated process): ILL_ILLOPN (ud2) at ip:2607064

    ip:2607064 - 0x200000 = opencode+0x2407064, byte-identical to this issue's documented ud2 site in OpenTUI's drawTextBuffer. With a fixed (non-PIE) base the same absolute RIP is expected; the noteworthy part is that >=14 such ILL_ILLOPN traps have landed since 2026-09-19 (several/hour at peak) across several independent install paths, and every one reports coredumpctl: missing - the SIGILL cores are silently dropped, so the only physical core from the whole run is a concurrent int3 halt in a third process (PID 71263, 157,990,957 B zst; happy to upload it if useful).

    OOM is ruled out (31 GiB RAM / 62 GiB swap never under pressure). The crash-time dlopened modules /tmp/libopentui.so and the fff Rust cdylib carry no GNU build-id, which blocks symbolization of library-local frames.

  8. hitcreate commented on Sep 25, 2026

    @hitcreate

    Confirming this on the current release, with a different trigger and a capturable core.

    Machine: cmdu-omarchy (Arch/Omarchy, Hyprland), opencode 1.18.32 via mise, embedded Bun build ID c30f169b1bef81fa57467cd091ba53aab5235468.

    New trigger — no TUI, no scale event. Ten opencode processes dumped core in ~110 s (2026-09-26 08:38:53–08:40:43 AEST). Every one was a headless opencode --port <n> server spawned by the VS Code extension sst-dev.opencode-0.0.13 (cgroup app-code-*.scope), on the main thread. Ports differ per hit (19815, 26174, 29644, 45325, 53669, …) — independent server instances being cycled and respawned, i.e. the extension's server keeps crashing and coming back. No interactive terminal, and no compositor scale/resize event in the journal; this sits closer to the extension/startup path than to the scale-to-4 trigger.

    Identical abort site, disassembled from a present core (143.3 MB, not missing):

    #0  opencode + 0x2407064       ; ud2
    #5  libopentui.so + 0x1d061d   ; OptimizedBuffer.trySetTransparentTextCellFast, buffer.zig:896
    
    • si_code = ILL_ILLOPN, si_addr = 0x2607064 = opencode+0x2407064; x/i $pc → ud2, int3 after. Confirms the deliberate Bun trap, not an unsupported AVX opcode.
    • The noreturn function ending at that ud2 resets dispositions to SIG_DFL via sigaction for SIGSEGV/SIGILL/SIGBUS/SIGABRT/SIGFPE/SIGHUP/SIGTERM; the literal beside it is Bun's banner "Bun has crashed. This indicates a bug in Bun, not your code." So the originating signal is not preserved in the core.
    • #5 resolves with DWARF to the same buffer.zig:896 text-cell path reported above.

    Not a 1.18.32 regression. coredumpctl list opencode shows the same signature for both 1.18.31 and 1.18.32 (older cores since rotated, missing) — upgrading didn't help, consistent with the note that the fix is in v2.

    Ruled out: OOM (17 GiB free + 120 GiB swap at diagnosis); data loss (SQLite opencode.db intact, -wal crash-safe).

    Given simonklee's note that the fix is in v2 with no 1.18.x patch planned: is there an expected release that will carry it, and would a present core (rather than another missing one) be useful to upload?

    Filed by deepseek-flash via opencode.

  9. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions