Skip to content

fix(desktop): make Linux AppImage GStreamer work on non-Debian distros#2176

Open
dcadenas wants to merge 2 commits into
block:mainfrom
dcadenas:fix/appimage-gstreamer-nondebian
Open

fix(desktop): make Linux AppImage GStreamer work on non-Debian distros#2176
dcadenas wants to merge 2 commits into
block:mainfrom
dcadenas:fix/appimage-gstreamer-nondebian

Conversation

@dcadenas

Copy link
Copy Markdown

Problem

The Linux AppImage opens a blank / fully transparent window on non-Debian
distros (Arch, Fedora, …): the transparent Tauri shell shows the desktop
through it because the WebKitWebProcess crashes (SIGABRT) during media-pipeline
init, logging:

GStreamer element appsink not found
GStreamer element appsrc not found
GStreamer element autoaudiosink not found

The .deb is unaffected; only the AppImage is broken, and only off
Debian/Ubuntu.

Root cause

Two things combine in desktop/scripts/fix-appimage.sh (the CI post-build
step):

  1. linuxdeploy's compiled AppRun.wrapped force-sets
    GST_PLUGIN_SYSTEM_PATH_1_0=$APPDIR/usr/lib/gstreamer-1.0. A set
    GST_PLUGIN_SYSTEM_PATH_1_0 replaces GStreamer's compiled-in default
    search path — it does not add to it.
  2. fix-appimage.sh populated $APPDIR/usr/lib/gstreamer-1.0 as an absolute
    symlink to the Debian multiarch path /usr/lib/x86_64-linux-gnu/gstreamer-1.0,
    which only exists on Debian/Ubuntu — so on Arch/Fedora the symlink dangles.

Result on non-Debian: GStreamer searches only a nonexistent directory → zero
plugins → appsink/appsrc/autoaudiosink missing → WebKit aborts → blank
window. The old comment claimed a dangling symlink "safely falls back to
default discovery"; that is false — a set GST_PLUGIN_SYSTEM_PATH_1_0 disables
the default.

(fix-appimage.sh already strips the bundled GStreamer core libs so the app
uses the host's GStreamer; the bug is purely that the plugin path was pinned
to a Debian-only location.)

Fix

Complete the script's existing "rely on the host's GStreamer" design. Instead
of pinning the plugin path to a hardcoded distro layout, install a small
launcher shim in front of the app binary that removes the bundle-pointing
GST_PLUGIN_* overrides after AppRun.wrapped sets them, so the system
GStreamer resolves plugins via its own default path — correct on Debian, Arch,
and Fedora alike.

Why a shim and not just unsetting the var in AppRun: AppRun.wrapped is a
compiled binary that rewrites GST_PLUGIN_SYSTEM_PATH_1_0 after every
apprun-hook, discarding any value set before it (verified empirically — a
runtime value passed in does not survive). The only place to neutralize the
override is between AppRun.wrapped and the real binary, i.e. on the exec
target usr/bin/buzz-desktop (moved aside to buzz-desktop.bin).

The shim only unsets values that point into the AppImage, so a user's own
GST_PLUGIN_* env is preserved. Fail-loud guards were added (verify
AppRun.wrapped still injects the override; verify the app binary exists;
refuse double-install) so a future tauri/linuxdeploy change is caught in CI,
not by users. Also removed a now-unused multiarch-detection block and renamed
the CI step.

Validation

Proven on Arch Linux (x86_64):

  • gst-inspect-1.0 with the override pointed at the dangling Debian dir →
    appsink/appsrc/autoaudiosink NOT FOUND; with it unset → all FOUND.
  • The shim, exercised through the real launch chain
    (AppRun → AppRun.wrapped → shim → app) against a fresh extract of the
    shipped AppImage: the forced override is stripped and the app process sees
    all three elements.
  • bash -n passes on the script and the generated shim.

Not yet tested (needs CI):

  • The full fix-appimage.sh extract → repack → sign path locally (no
    appimagetool on hand; the only local AppImage is already fix-processed,
    which the libwayland guard correctly refuses to re-process).
  • Actual GUI window paint from a freshly-built AppImage on a non-Debian distro.

Files

  • desktop/scripts/fix-appimage.sh — shim replaces the dangling symlink;
    guards; corrected comments; removed unused multiarch block.
  • .github/workflows/release.yml — step name updated.

@dcadenas
dcadenas requested a review from a team as a code owner July 20, 2026 16:25
…tros

Signed-off-by: Daniel Cadenas <dcadenas@gmail.com>
@dcadenas
dcadenas force-pushed the fix/appimage-gstreamer-nondebian branch from 93f5b2e to 480b5ee Compare July 20, 2026 16:27

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

hey Daniel — the root-cause analysis here is right and well-evidenced (a set GST_PLUGIN_SYSTEM_PATH_1_0 replaces GStreamer's default search path, so the old Debian-multiarch symlink was a Debian-only accident), and the shim placement after AppRun.wrapped is the only spot that works. The Arch validation through the real AppRun → AppRun.wrapped → shim → app chain is exactly the right disproving test. The fail-loud guards are great too.

Requesting changes for two small hardenings (comments 1 and 2 inline — one flag and one character respectively). Comments 3 and 4 are nits, take or leave. None of this changes the approach.

Comment thread desktop/scripts/fix-appimage.sh Outdated
unset "$var"
fi
done
exec "$here/buzz-desktop.bin" "$@"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the bare exec makes argv[0] …/buzz-desktop.bin. GTK derives prgname → WM_CLASS from argv[0], so taskbar icon matching / window grouping against the .desktop file can break, and pidof/killall buzz-desktop stop working. One flag fixes it:

exec -a "buzz-desktop" "$here/buzz-desktop.bin" "$@"

Separately, the kernel comm comes from the exec'd file's basename (not argv[0], so exec -a doesn't cover this leg): buzz-desktop.bin truncates to buzz-desktop.bi, which no longer matches DESKTOP_BINARY_NAMES in desktop_is_alive_for_instance (runtime.rs:761 / :955). I checked and this isn't a new regression — release Linux builds already fail that function's cmdline leg (the instance id only appears in /proc/pid/cmdline for tauri dev --config launches), so release desktops are already invisible to reap_dead_instance_agents on main. A companion line adding buzz-desktop.bi to DESKTOP_BINARY_NAMES would close the comm leg for whenever the cmdline leg gets fixed — fine as a fast-follow if you'd rather keep this PR tight.

@dcadenas dcadenas Jul 21, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in 8f3003f. The shim now uses exec -a "buzz-desktop" to preserve argv[0], and I also added the Linux-truncated buzz-desktop.bi name to DESKTOP_BINARY_NAMES with a focused regression test.

Comment thread desktop/scripts/fix-appimage.sh Outdated
GST_PLUGIN_PATH_1_0 GST_PLUGIN_PATH \
GST_PLUGIN_SCANNER GST_PLUGIN_SCANNER_1_0; do
val="${!var-}"
if [[ -n "$val" && "$val" == *"$appdir"* ]]; then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

*"$appdir"* is a loose substring match — if someone runs the extracted AppDir from e.g. /opt/buzz, a user-set GST_PLUGIN_PATH=/opt/buzz-plugins would falsely match and get unset. *"$appdir/"* still matches the injected $APPDIR/usr/lib/gstreamer-1.0 and kills the false positive. One character.

@dcadenas dcadenas Jul 21, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in 8f3003f. The match now requires $appdir/, so the injected in-AppImage paths are removed without falsely matching sibling paths such as /opt/buzz-plugins.

# The real binary moves aside; buzz-desktop becomes a shim AppRun.wrapped execs.
mv "$APP_BIN" "$APP_BIN.bin"
cat > "$APP_BIN" <<'SHIM'
#!/usr/bin/env bash

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit (non-blocking): the shim adds a hard runtime dep on bash + readlink -f (coreutils). Both are universally present on the distros we target so I wouldn't hold anything on this, but a POSIX-sh shim would be marginally more portable if you feel like it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Keeping Bash intentionally here: the blocking process-name fix relies on Bash's exec -a, which POSIX sh does not provide portably. bash and readlink -f remain available on the Linux distributions we target.

Comment thread desktop/scripts/fix-appimage.sh Outdated
# silently ship — so fail loudly (mirrors the libwayland guard above).
APPRUN_WRAPPED="$WORKDIR/squashfs-root/AppRun.wrapped"
if ! grep -aq "GST_PLUGIN_SYSTEM_PATH_1_0" "$APPRUN_WRAPPED"; then
echo "Error: AppRun.wrapped no longer references GST_PLUGIN_SYSTEM_PATH_1_0 — GStreamer path injection changed; re-verify fix-appimage.sh" >&2

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit (non-blocking): this guard also fires when AppRun.wrapped is missing entirely (grep's exit 2 under if ! — which is good, that's the right behavior), but then the message says the file "no longer references" the var when the file doesn't exist. Behavior's right, wording's slightly off — maybe cover both cases in the message.

@dcadenas dcadenas Jul 21, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in 8f3003f. The guard now says AppRun.wrapped may be missing or may no longer reference the variable, covering both grep failure cases accurately.

Signed-off-by: Daniel Cadenas <dcadenas@gmail.com>
@dcadenas
dcadenas force-pushed the fix/appimage-gstreamer-nondebian branch from 5297f9a to 8f3003f Compare July 21, 2026 23:03
@dcadenas
dcadenas requested a review from wpfleger96 July 21, 2026 23:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants