Skip to content

tui: leaks ~21MB .so per launch into /tmp; fills tmpfs and breaks TUI startup #42700

Description

@jsongalvez

Summary

The TUI leaks a ~21 MB .so file into the temp directory on every launch and never cleans it up. After many launches the temp filesystem fills up, and the TUI then fails to start with an OpenTUI library load error.

Environment

  • opencode version: 0.0.0-next-17444
  • OS: Arch Linux, kernel 7.1.3-arch2-2 (linux x64)
  • Terminal: xterm-256color (also reproduced over SSH from a phone terminal)
  • Shell: /usr/bin/bash
  • Install/channel: next (npm global install)
  • Active plugins: none active; config lists a local skill plugin (ponytail.mjs) and a local plugin (caveman/plugin.js) — unrelated to this failure, TUI fails with plugins disabled too

Reproduction

  1. Run opencode2 (TUI) in a terminal, exit it. Repeat the launch several times (each launch generates a fresh extraction).
  2. Check the temp directory: ls -la /tmp | grep '\.so$' — each launch adds a file like .39dbfbfdbf6bfbff-00000000.so (~21 MB, random hash prefix per launch). 2,338 files / ~13 GB accumulated over days of normal use on this machine.
  3. Once the temp filesystem is full, the TUI fails at startup:
ERROR (#1): Error: Failed to initialize OpenTUI render library: Failed to open library "/$bunfs/root/libopentui-6wc2mm41.so": /$bunfs/root/libopentui-6wc2mm41.so: cannot open shared object file
    at Y0 (../../node_modules/.bun/@opentui+core@0.5.3+2240c214a0f33214/node_modules/@opentui/core/chunk-bun-26r5c5w5.js:17303:17)
    at new F8 (.../node_modules/.bun/@opentui+core@0.5.3+2240c214a0f33214/node_modules/@opentui/core/chunk-bun-t68f2fmr.js:7236:17)

Expected Behavior

The extracted library file is either reused across launches (stable name / extracted once) or removed when the TUI exits. The temp directory should not grow unboundedly.

Actual Behavior

Every TUI launch extracts a fresh hashed .so (~21 MB) into $TMPDIR (default /tmp) and leaves it there. On this machine the files accumulated to ~13 GB, filling the tmpfs and causing the startup failure above. Clearing /tmp/.[0-9a-f]*-*.so restores normal operation (2,338 files deleted, 13 GB reclaimed). Other processes doing large tmpfs writes (Gradle/Kotlin daemons, build tools) make the failure arrive sooner.

Additional Context

  • Workaround: rm /tmp/.[0-9a-f]*-*.so (safe — the running TUI keeps the loaded library mapped; a daily cron purge was installed to keep the box usable).
  • The hashed names match bun's embedded-filesystem extraction pattern (bunfs), so this likely affects any bun-compiled binary that extracts libraries into the temp dir without cleanup.
  • Frequency: every launch; the failure itself appears once the temp filesystem is full, which took ~2 days of frequent TUI use here.

Activity

  1. github-actions commented on Aug 15, 2026

    @github-actions
    Contributor

    This issue might be related to an existing open issue that covers the same root cause. Please check:

    Your report is distinct in that it focuses on the interactive TUI itself leaking on every launch (rather than headless commands), so it may warrant tracking separately if the fix scopes differ.

  2. thdxr commented on Aug 19, 2026

    @thdxr
    Member

    Update: the unbounded native-library temp-file growth described here is fixed in OpenCode V2.

    As of V2 build 0.0.0-dev-17643, the compiled CLI uses Bun 1.4.0-canary.1 (681a49bee). That runtime includes oven-sh/bun#29587, which replaces the unique temporary .so/.dylib/.node extraction on every load with a deterministic, content-hashed path reused across calls, Workers, processes, and restarts. The V2 build provenance is workflow run 32216069554.

    This bounds extraction to one reusable file per embedded native module and user instead of allowing unbounded disk growth. It does not mean the temp directory will contain zero native files, and upgrading does not remove files leaked by older builds; those stale randomly named files can be cleaned up after all older OpenCode processes have stopped.

  3. ryanseddon commented on Aug 20, 2026

    @ryanseddon

    Interestingly I couldn't update opencode2 via curl as I had this issue with the .so files causing the crash.

    When I ran: curl -fsSL https://opencode.ai/v2/install | bash

    I got: curl: (23) Failure writing output to destination, passed 1369 returned 1367

    Once I ran find . -name "/tmp/*.so" -type f -delete

    Then curl worked fine. Also curl seems to get version 0.0.0-dev-17639 from curl so assume 643 isn't updated yet?

  4. jsongalvez commented on Aug 20, 2026

    @jsongalvez
    Author

    Interestingly I couldn't update opencode2 via curl as I had this issue with the .so files causing the crash.

    When I ran: curl -fsSL https://opencode.ai/v2/install | bash

    I got: curl: (23) Failure writing output to destination, passed 1369 returned 1367

    Once I ran find . -name "/tmp/*.so" -type f -delete

    Then curl worked fine. Also curl seems to get version 0.0.0-dev-17639 from curl so assume 643 isn't updated yet?

    you can force curl to install the beta release channel using curl -fsSL https://opencode.ai/v2/install|bash -s -- --version 0.0.0-beta-17639

    you run npm view @opencode-ai/cli dist-tags --json to view the different tags

    [
      {
        "tui-v2": "0.0.0-tui-v2-202606261840",
        "latest": "1.18.18",
        "next": "0.0.0-beta-17498",
        "beta": "0.0.0-beta-17639",
        "dev": "0.0.0-dev-17706"
      }
    ]
    
  5. juanvs23 commented on Aug 25, 2026

    @juanvs23

    Occurrence report — additional diagnostic evidence (opencode 1.18.23, stable channel)

    Confirming this also reproduces on the stable channel (1.18.23, Linux x86_64), plus one new data point: extraction happens not only per launch, but also during active session activity while the TUI stays open.

    Measurements from this machine:

    • Accumulation rate during active use: ~5 new .so blobs/min tied to session/turn bursts; 57 files (~634 MB) piled up within a single working day on a tmpfs-backed /tmp — i.e. it consumed RAM directly. A previous heavy-use day reached ~2,000 files / ~11 GB.
    • Every extracted copy is byte-identical: all sampled files share the same size (13,745,312 bytes) and md5 — it is the same embedded libopentui.so re-extracted over and over (SONAME confirmed via readelf -d; Zig-built ELF with debug info).
    • No process keeps an fd open after creation (lsof on the files returns nothing, and a deleted-fd scan comes up empty). The library appears to be mapped once and the temp file abandoned, so deleting while the TUI is running was safe here as well.
    • Creation stops entirely while the session is idle: a 70-second idle watch produced zero new files; creation resumed immediately with session activity. This suggests per-turn/per-burst re-initialization rather than a single per-process extraction.

    Workarounds currently in place (both effective so far):

    • Launching with TMPDIR pointed at a disk-backed directory → leak lands on disk instead of tmpfs RAM.
    • Hourly cron purge: find /tmp -maxdepth 1 -regextype posix-extended -regex '.*/\.[0-9a-f]{16}-00000000\.so' -mmin +90 -delete

    Happy to test a candidate fix (stable-name reuse or exit-time cleanup) if useful.

  6. bit0x43 commented on Aug 26, 2026

    @bit0x43

    macOS (arm64) variant: continuous .dylib leak during a session, ~1.6 GB/hour

    Same root mechanism as this report (bunfs embedded-library extraction into the temp dir with no cleanup), but on macOS the artifact extension is .dylib and the leak is continuous while a session runs, not just once per launch. Worth fixing here since it fills internal SSDs on Macs quickly.

    Environment

    • opencode 1.18.23, macOS 26.6.2 (build 25G83), arm64
    • Bundled Bun runtime v24.18.0

    Observed behavior

    • Files matching $TMPDIR/.5bff*-00000000.dylib (also saw .5bfe*, .b9de*, .b9df* prefixes over time) — Mach-O 64-bit dynamically linked shared library, arm64, ~3.6 MB each.
    • Leak is continuous during active usage, not one file per launch: measured 9,316 files / 33 GB accumulated in ~21 hours ≈ 1.6 GB/hour (~one file every 8 s), with lsof showing the running opencode process holding them open.
    • On a 256 GB-class internal SSD this drove the disk to ~50% full within a day; a prior occurrence reached ~71 GB before manual cleanup.

    Reproduction

    1. Run opencode TUI, keep an active session going for a few hours.
    2. find "$TMPDIR" -maxdepth 1 -name '.5bff*-*.dylib' | wc -l → grows hundreds of files/hour.
    3. lsof +D "$TMPDIR" → owned by the opencode process.

    Expected behavior

    Extracted runtime libraries are either reused across launches / stable-named or removed when no longer needed. The temp dir should not grow unboundedly during a single session.

    Workaround (safe on macOS)

    Deleting an open file on macOS is safe — space is reclaimed when the holding process exits and Bun re-JITs on demand:

    find "$TMPDIR" -maxdepth 1 -type f -name '.*-*.dylib' -delete
    

    I installed a 30-minute purge agent to contain this; that is mitigation, not a fix.

    Notes

  7. jpwerner2505 commented on Aug 29, 2026

    @jpwerner2505

    Another data point for this, with a failure mode I don't see covered in the existing reports: on a distro that puts a per-user quota on /tmp, this bug bites at 80% of the tmpfs, not 100%, and it takes down unrelated programs rather than opencode itself.

    Environment

    • opencode: 1.18.25 (standalone binary, ~/.opencode/bin/opencode, 184 MB)
    • OS: Fedora Linux 44 (KDE Plasma), kernel 7.1.10-200.fc44.x86_64
    • systemd: 259 (259.8-1.fc44)
    • Terminal: xterm-256color

    What accumulated

    1010 byte-identical copies of the extracted library, ~6.2 GB total:

    $ ls -1 /tmp/.*-00000000.so | wc -l
    1010
    $ du -shc /tmp/.*-00000000.so | tail -1
    6,2G  total
    $ md5sum /tmp/.9adb5ebfeaedff8f-00000000.so /tmp/.9adb5ef9ffe6ed87-00000000.so
    d08bd9a52225cacba076f60cca5a697e  ...
    d08bd9a52225cacba076f60cca5a697e  ...   # identical
    $ objdump -p /tmp/.9adb5ebfeaedff8f-00000000.so | grep SONAME
      SONAME               libopentui.so
    

    Each file is 13,745,312 bytes (13.10 MiB) — smaller than the ~21 MB reported in the issue body, so the size tracks the opentui/bun version. Timestamps spanned 19:48–22:59 on a single day: ~1010 launches accumulated in about three hours of normal use.

    Why the quota makes this worse

    Fedora 44 ships systemd's stock tmp.mount, which enables tmpfs user quota:

    Options=mode=1777,strictatime,nosuid,nodev,size=50%,nr_inodes=1m,x-systemd.graceful-option=usrquota
    

    The default per-user limit is 80% of the filesystem. So on a 7.8 GB /tmp the ceiling is 6360 MB, and the leak hit it while df still showed 20% free:

    $ df -h /tmp
    tmpfs  7,8G  6,3G  1,6G  80% /tmp
    $ quota -s -u <user>
         Filesystem   space   quota   limit   grace
              tmpfs  6359M   6360M   6360M
    

    The part that cost the most time to diagnose

    opencode itself kept working. What broke was everything else that writes to /tmp, and it broke silently. Writes returned EDQUOT, which surfaced as shells that exit 1 with empty stdout and empty stderr — the failing component never got to report anything:

    $ echo hello        # exit 1, no output
    $ true              # exit 1, no output
    

    true returning 1 is what finally gave it away: the shell was dying before executing anything, because its wrapper couldn't create a temp file. Any tool that stages work through /tmp shows the same shape — it just stops, with no error to search for. Tracking it back to opencode took reading /proc/mounts to spot usrquota, then objdump -p on one of the files to get SONAME: libopentui.so.

    Worth noting for the fix discussion: usrquota on /tmp is stock systemd ≥ 256 behaviour, not a Fedora patch, so this "fails early and blames the wrong process" mode will get more common as distros pick up newer systemd.

    Confirming the files are orphans

    None of the 1010 copies were mapped by any live process, so they are pure garbage rather than in-use libraries:

    $ lsof /tmp/.*-00000000.so | wc -l
    0
    $ ls -l /proc/*/map_files/ 2>/dev/null | grep -c '00000000.so'
    0
    

    Deleting them reclaimed the full 6.2 GB and restored /tmp to 1% used, with no restart needed.

    Workaround

    Since r lines in tmpfiles.d don't accept an age field and systemd-tmpfiles --clean doesn't process them, a tmpfiles.d rule alone can't express "delete files matching this glob older than N minutes". A systemd user timer works without root:

    # ~/.local/bin/clean-opentui-tmp.sh
    find /tmp -maxdepth 1 -type f -user "$(id -u)" -name '.*-00000000.so' -mmin +60 -print0 |
      while IFS= read -r -d '' f; do
        lsof -- "$f" >/dev/null 2>&1 || rm -f -- "$f"
      done

    driven hourly by OnUnitActiveSec=1h. The -mmin +60 and lsof guards are belt-and-braces — deleting a mapped .so is safe on Linux, since the inode survives until unmapped — but they keep the purge from racing a launch that has just extracted its copy.

  8. liamhendricks commented on Sep 9, 2026

    @liamhendricks

    Genuinely impressed that an open source project this big can be leaking gigabytes of data per day and it goes unfixed. Pretty embarrassing tbh. Also caused me to lose several hours of work so fuck you guys.

  9. rekram1-node commented on Oct 8, 2026

    @rekram1-node
    Collaborator

    this was due to a bug in bun itself, opencode v2 uses bun 1.4+ instead which does not have the same issue.

    https://opencode.ai/v2/docs

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions