Skip to content

Shell tool crashes with SIGTRAP on linux/arm64 (web-tree-sitter Parser.init in JSC) #34054

Closed as not planned

Description

@darius-f96

Summary

On linux/arm64, OpenCode crashes with SIGTRAP the first time the shell tool runs any command. The crash happens inside web-tree-sitter's Parser.init() (WASM module initialization), which the shell tool calls to scan a command for the paths it touches (used by the permission system).

Because every shell command triggers this path, OpenCode is effectively unusable on linux/arm64.

Environment

  • Platform: linux/arm64 (aarch64) — reproduced on an NVIDIA GB10 (Grace, ARMv9)
  • Bun: 1.3.14
  • web-tree-sitter: 0.25.10
  • OpenCode: built from source on current dev

Repro

  1. Build/run OpenCode on a linux/arm64 host with Bun 1.3.14.
  2. Issue any prompt that makes the model run a shell command (e.g. ls).
  3. Process dies with SIGTRAP before the command runs.

Root cause

The fault originates in JavaScriptCore when web-tree-sitter initializes its WASM modules via Parser.init() in packages/opencode/src/tool/shell.ts (the parse() helper, ~line 312).

The faulting address is 0xE3C500000012 — above the 48-bit virtual-address space — which points at tagged-pointer / NaN-boxing corruption in JSC on aarch64 rather than a logic bug in OpenCode itself. So this is fundamentally a Bun/JSC-on-aarch64 issue, but it makes OpenCode crash hard (a SIGTRAP panic can't be caught from JS).

Impact / tradeoff

The tree-sitter scan exists only to feed the permission system (detecting which directories a command would access). On linux/arm64 today the choice is binary: crash on every command, or skip the scan. There's no graceful in-JS fallback because the panic is uncatchable.

Proposed fix

Guard the scan so it's skipped on linux/arm64, keeping OpenCode usable on the platform. Downside: the directory-access permission scan is disabled there until the upstream Bun/JSC issue is fixed. Happy to gate it more narrowly (env opt-out, warn-once, etc.) if the team prefers — opening a PR with the minimal version and will reference this issue.

Is there a preferred direction here before I finalize the PR?

Activity

  1. opencode-agent commented on Jun 26, 2026

    @opencode-agent
    Contributor

    Hi — I’m an AI coding agent assisting the OpenCode team. I tried to independently reproduce this before the next release, but could not reproduce the SIGTRAP with the evidence currently available.

    I tested the same reported runtime/dependencies under ARM64 emulation:

    • Bun 1.3.14 ARM64 (0d9b296a)
    • [email protected]
    • [email protected]
    • the repository's exact Parser.init() → Bash WASM load → parse path
    • QEMU CPU models max, neoverse-n1, and cortex-a76

    The minimal parser path passed 25/25 runs. I also ran packages/opencode/test/tool/shell.test.ts under ARM64 emulation: 19 tests passed, with four unrelated emulation/subprocess failures, and no parser crash or SIGTRAP.

    I also checked history: current dev, v1.17.10, and v1.17.11 have the identical packages/opencode/src/tool/shell.ts blob. Parser.init() has been in this path since October 2025, and the Bun/tree-sitter versions are unchanged from v1.17.9 through current dev. So I could not identify a recent shell-tool change that explains this report.

    This does not rule out a native NVIDIA Grace/GB10-specific JSC failure; QEMU is not equivalent to that hardware. Could you provide a tighter reproduction so we can validate it natively?

    1. Exact OpenCode commit SHA tested (not only “current dev”).
    2. Full raw crash output, including Bun stack/signature and fault address.
    3. Whether this minimal standalone script crashes on the GB10:
    import { fileURLToPath } from "node:url"
    import { Parser, Language } from "web-tree-sitter"
    import treeWasm from "web-tree-sitter/tree-sitter.wasm" with { type: "wasm" }
    import bashWasm from "tree-sitter-bash/tree-sitter-bash.wasm" with { type: "wasm" }
    
    const path = (asset: string) =>
      asset.startsWith("file://") ? fileURLToPath(asset) : asset.startsWith("/") ? asset : fileURLToPath(new URL(asset, import.meta.url))
    
    await Parser.init({ locateFile: () => path(treeWasm) })
    const language = await Language.load(path(bashWasm))
    const parser = new Parser()
    parser.setLanguage(language)
    console.log(parser.parse("echo hello").rootNode.toString())
    1. Results for that script on v1.17.9, v1.17.11, and the reported dev SHA.
    2. Whether BUN_JSC_useWasmIPInt=0 changes the result.

    A minimal repo or exact command transcript would be especially helpful. Thanks.

  2. darius-f96 commented on Jun 27, 2026

    @darius-f96
    Author

    Reproduced on native hardware — official 1.17.9, Bun's own panic. Answering your five questions:

    1. Exact opencode commit / version tested

    • Official opencode 1.17.9 (the released opencode-linux-arm64 binary — not my fork). The crash below is from it.
    • Bun: v1.3.14 (0d9b296a), Linux arm64, kernel 6.17.0, glibc 2.39.
    • Deps as before: [email protected], [email protected].

    2. Full raw crash output (Bun signature + fault address)

    Captured live during a real agent run (opencode run --agent plan --dir <repo>):

    ============================================================
    Bun v1.3.14 (0d9b296a) Linux arm64
    Linux Kernel v6.17.0 | glibc v2.39
    CPU: neon fp aes crc32 atomics sve
    Args: ".../opencode" "--user-agent=opencode/1.17.9" "--use-system-ca" "--" "run" "--agent" "plan" "--dir" ...
    Elapsed: 123843ms | User: 21809ms | Sys: 2748ms
    RSS: 69.93MB | Peak: 0.64GB | Commit: 69.93MB | Faults: 1
    
    panic: Segmentation fault at address 0xEA8E00000012
    oh no: Bun has crashed. This indicates a bug in Bun, not your code.
    
    https://bun.report/1.3.14/La10d9b296mgGugogCmw2wqE+lFmmu9yEmmu9yEujxt/E+5kjgFuvz/8E+1/wqE21shB2096BA28o1DkB
    

    The bun.report link carries the symbolicated stack for the Bun team.

    Fault-address pattern (important): an earlier capture on this box faulted at 0xE3C500000012; this one at 0xEA8E00000012. Both end in …00000012 — identical low 32 bits (offset 0x12), only the high 16 bits differ (ASLR-varied). Two independent crashes with the same field offset → a consistent tagged-pointer / NaN-box corruption in JSC, dereferencing a corrupted JSValue at +0x12. Not random memory.

    3. Does the minimal standalone script crash on this hardware?

    No. I ran your exact script natively on the GB10 plus escalations — none crash:

    • your script verbatim → OK
    • 200,000-iteration parse loop (force JSC Wasm tier-up) → OK
    • 8 concurrent workers × 40,000 iters, each a full cursor walk (gotoFirstChild/namedChildren/.text) + GC pressure → OK
    • all of the above compiled with bun build --compile → OK

    So Parser.init() + parse in isolation is not sufficient. The crash only manifests inside the full opencode runtime, intermittently (it took many real agent sessions to fire one), and — notably — this capture crashed in the plan agent while doing file Reads of a large source file, not in the shell-tool WASM init. So this is a broader JSC corruption, not specific to web-tree-sitter (which only happened to be one trigger). My shell.ts guard sidesteps one path; the underlying JSC bug is wider.

    4. v1.17.9 / v1.17.11 / dev

    • v1.17.9 (official): crashes (above).
    • Same shell.ts blob across versions per your check; the bug is in Bun/JSC, not opencode source, so version-to-version opencode diffs aren't the variable.

    5. BUN_JSC_useWasmIPInt=0

    No observable change — but inconclusive, since I can't trigger the crash deterministically in isolation to A/B it, and this capture wasn't in the Wasm interpreter path anyway.


    The likely missing variable: SVE / Neoverse-V2

    Note the crash report's CPU: neon fp aes crc32 atomics **sve**. This is an NVIDIA GB10 (Grace, ARM Neoverse-V2) with SVE (Scalable Vector Extension). Your QEMU CPU models (max, cortex-a76, neoverse-n1) do not implement Neoverse-V2 / SVE the way real V2 silicon does — that's very likely why QEMU never reproduced. Recommend testing on real Grace/GH200/GB10, or QEMU -cpu neoverse-v2,sve=on.

    Summary for the Bun team: intermittent JSC tagged-pointer corruption (fault always …+0x12) under sustained real workload on Neoverse-V2 + SVE + Bun 1.3.14, reproducible in official opencode 1.17.9. bun.report link above has the stack.

  3. github-actions commented on Aug 27, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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