Skip to content

fix(desktop): build AppImage with the static runtime toolset (fixes libfuse2 launch failure) - #7765

Open
Bombatomica64 wants to merge 2 commits into
pingdotgg:mainfrom
Bombatomica64:fix/appimage-static-runtime-fuse3
Open

fix(desktop): build AppImage with the static runtime toolset (fixes libfuse2 launch failure)#7765
Bombatomica64 wants to merge 2 commits into
pingdotgg:mainfrom
Bombatomica64:fix/appimage-static-runtime-fuse3

Conversation

@Bombatomica64

@Bombatomica64 Bombatomica64 commented Aug 21, 2026

Copy link
Copy Markdown

Problem

The Linux AppImage cannot launch on any distro that has dropped FUSE 2. It dies before Electron starts:

dlopen(): error loading libfuse.so.2

AppImages require FUSE to run.

I'm on Linux and the AppImage is how I run T3 Code, so this takes the app out entirely. On Debian forky there is no local fix — libfuse2/libfuse2t64 has been removed from the archive (apt-cache policy returns no candidate), so the sudo apt install libfuse2 workaround from the existing issues simply doesn't apply. FUSE 2 is EOL upstream, so more distros will land here over time, not fewer.

Previously reported in #1482 and #4465 (the latter open since July with no response).

Cause

Not the app — the packaging default. In app-builder-lib 26.15.6 (the version pinned in apps/desktop/package.json) the runtime is selected by:

const isFuse2 = appimageToolVersion === "0.0.0" || appimageToolVersion == null;

Unset/null selects the legacy FUSE 2 bundle. toolsets appears nowhere in this repo, so builds silently inherit that default.

Fix

Pin the static toolset, which app-builder-lib 26.15.6 already supports — no dependency bump required:

buildConfig.toolsets = { appimage: "1.0.3" };

Set inside the platform === "linux" branch, so macOS and Windows toolsets are untouched.

electron-builder v27 flips this default (isFuse2 = toolset === "0.0.0", explicit opt-in only) via the toolset overhaul in #9939. This brings the fix forward without waiting on the v27 breaking release.

Verification

The runtime actually changes. I downloaded the 1.0.3 toolset and confirmed its SHA-256 matches the appimageChecksums["1.0.3"] entry in app-builder-lib 26.15.6 (84021a78…c7fe084021a78ee214ae6fd33a2d62a92ba25542dd10bc86bf117a9b2d0bba44e7665), then compared runtimes:

shipped 0.0.34-nightly.20260821.1149 toolset 1.0.3 (runtime 20251108)
linkage dynamically linked static-pie linked
libfuse.so.2 present absent
squashfuse 0.1.100 0.5.2

The current runtime carries libfuse.so.2 and the dlopen() error string; the proposed one is statically linked and has no FUSE dependency at all.

Tests (scripts workspace, vp test run):

  • build-desktop-artifact.test.ts46/46 pass with the change.
  • Negative control: deleting the new line makes exactly 1 test fail with expected undefined to deeply equal { appimage: '1.0.3' }, so the assertion is meaningful rather than vacuous.
  • Full scripts suite — 234/235 pass. The single failure is lib/cli-external-packages.test.ts ("expected node-pty in the pnpm store"), which is an artifact of my filtered pnpm install --ignore-scripts and reproduces identically on pristine main with this PR's changes reverted. Unrelated to this change.
  • tsgo --noEmit on scripts — clean, exit 0.

End-to-end packaged build. I ran node scripts/build-desktop-artifact.ts --platform linux --target AppImage --arch x64 on Debian forky (FUSE 3 only, no libfuse2 installed anywhere on the system). It completed cleanly, exit 0, producing a 143 MB T3-Code-0.0.33-x86_64.AppImage. Its runtime is static-pie linked, BuildID a87aaf5da1…, matching the 1.0.3 runtime exactly.

The resulting AppImage mounts on a machine where the current release cannot — same host, same flag, back to back:

# built from this PR
$ T3-Code-0.0.33-x86_64.AppImage --appimage-mount
/tmp/.mount_T3-CoddPCnao          <- mounts

# current 0.0.34-nightly.20260821.1149
$ T3-Code-0.0.34-nightly...AppImage --appimage-mount
dlopen(): error loading libfuse.so.2
AppImages require FUSE to run.    <- fails

mount confirms a real FUSE mount, and Electron boots from it (AppRun off the mountpoint initialises its user-data dir). My run then exits via the existing single-instance lock because another copy was already running on this box — the behaviour described in #4465 — so I have not verified a full cold UI session end to end, only that the runtime mounts and the app starts from it. That is precisely the part this PR changes.

Still worth confirming in CI: the electron-updater AppImageUpdater in-place update path, since the runtime is what gets swapped.

Note on the toolset version

1.0.2/1.0.3 are labelled "Betas" in electron-builder's typings (1.0.3 notes it resolves electron-builder#9598). If you'd rather not ship a beta toolset, the alternative is waiting for v27 — but that leaves the AppImage unlaunchable on modern distros until then.

For anyone hitting this before a release: APPIMAGE_EXTRACT_AND_RUN=1 works around it without root, since it skips mounting entirely.

🤖 Generated with Claude Code

electron-builder defaults `toolsets.appimage` to the legacy "0.0.0" bundle,
whose type-2 runtime is dynamically linked against libfuse.so.2. Distros that
ship only FUSE 3 cannot mount it, so the AppImage exits before Electron starts.

Pin the 1.0.3 bundle (runtime 20251108), which is statically linked and needs
no FUSE. Scoped to the linux branch so mac/win toolsets are unchanged.
electron-builder defaults `toolsets.appimage` to the legacy "0.0.0" bundle,
whose type-2 runtime is dynamically linked against libfuse.so.2. Distros that
ship only FUSE 3 cannot mount it, so the AppImage exits before Electron starts.

Pin the 1.0.3 bundle (runtime 20251108), which is statically linked and needs
no FUSE. Scoped to the linux branch so mac/win toolsets are unchanged.
Copilot AI lite review requested due to automatic review settings August 21, 2026 08:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bd0d77bc-933e-4c03-a1a0-b5413b6349ce

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Aug 21, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at fb47554

Macroscope's review found this PR approvable — This change pins the AppImage toolset version to fix a libfuse2 dependency issue on newer Linux distros. It's a minor build configuration tweak with no runtime behavior impact, includes test coverage, and is well-documented.

You can add or adjust custom eligibility rules. Learn more.

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

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants