Tauri Apps Built as Appimages are not working on modern linux distributions, like fedora, arch
Appimages are one of the nicest ways to distribute an app but not being able to run a format meant to be used on multiple os, is a bad thing. Appimage as a format is crucial for users who want to test a app and use it without the need of installing. Appimages are cool as they comes with all the required dependencies and can be operated on systems such as Windows with WSL2 and FreeBSD with the Linuxulator. Appimages are self contained in nature and requires no root access.

Gtk-Message: 21:07:08.168: Failed to load module "appmenu-gtk-module": 'gtk_module_display_init': /usr/lib64/gtk-3.0/modules/libcolorreload-gtk-module.so: undefined symbol: gtk_module_display_init
Could not create default EGL display: EGL_BAD_PARAMETER. Aborting...
** (apiark:185476): WARNING **: 21:07:33.334: atk-bridge: get_device_events_reply: unknown signature
This is a sample app image for a Tauri based rest-api client apiark.
So, I was building Drawx, the offline version of drawy, which provides data sovereignty because nothing ever leaves your machine. However, the Drawx app was not working on my machine because of some odd issues. I wanted to run the AppImage in a portable manner, but using environment variables did not help. Setting WEBKIT_DISABLE_DMABUF_RENDERER=1 or WEBKIT_DISABLE_COMPOSITING_MODE=1 either caused a crash on launch or displayed a blank screen. The issue is that the CI environment adds libraries such as libwayland-client.so inside the AppImage. This creates conflicts between the AppImage’s dependencies and the system’s libraries. The solution is to remove the duplicated dependencies and let the AppImage use the system’s libraries instead of those inside the AppImage.
How to Fix This ?
fixing missing libraries
Have composed a shell script to fix the issue. Create a file src-tauri/scripts/patch-appimage-wayland.sh and paste the script inside
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="")" && pwd)"
REPO_ROOT=""
SRC_TAURI_DIR="$REPO_ROOT/src-tauri"
TAURI_CACHE_DIR="/tauri"
# Clean up temp files on exit
TEMP_BIN=
TEMP_EXTRACT=""
cleanup() {
rm -rf "$TEMP_BIN"
if [ -n "$TEMP_EXTRACT" ] && [ -d "$TEMP_EXTRACT" ]; then
rm -rf "$TEMP_EXTRACT"
fi
}
trap cleanup EXIT
# 1. Resolve linuxdeploy and appimage tools
LINUXDEPLOY_BIN=""
if [ -d "$TAURI_CACHE_DIR" ]; then
cached_linuxdeploy=
if [ -n "$cached_linuxdeploy" ] && [ -f "$cached_linuxdeploy" ]; then
ln -sf "$cached_linuxdeploy" "$TEMP_BIN/linuxdeploy"
LINUXDEPLOY_BIN="$TEMP_BIN/linuxdeploy"
fi
cached_plugin=
if [ -n "$cached_plugin" ] && [ -f "$cached_plugin" ]; then
ln -sf "$cached_plugin" "$TEMP_BIN/linuxdeploy-plugin-appimage"
fi
fi
if [ -z "$LINUXDEPLOY_BIN" ] && command -v linuxdeploy >/dev/null 2>&1; then
LINUXDEPLOY_BIN=""
fi
export PATH="$TEMP_BIN:$PATH"
export APPIMAGE_EXTRACT_AND_RUN=1
# 2. Patch an AppDir in-place
patch_appdir() {
local appdir="$1"
echo "Patching AppDir: $appdir"
# 1. Write self-contained Wayland compatibility hook
mkdir -p "$appdir/apprun-hooks"
cat << 'EOF' > "$appdir/apprun-hooks/wayland-compat.sh"
export DESKTOPINTEGRATION=1
if [ -z "${LD_PRELOAD:-}" ]; then
for lib in \
/usr/lib/libwayland-client.so \
/usr/lib64/libwayland-client.so \
/usr/lib/x86_64-linux-gnu/libwayland-client.so \
/usr/lib/aarch64-linux-gnu/libwayland-client.so \
/usr/lib/arm-linux-gnueabihf/libwayland-client.so; do
if [ -f "$lib" ]; then
export LD_PRELOAD="$lib"
break
fi
done
fi
EOF
chmod +x "$appdir/apprun-hooks/wayland-compat.sh"
# 2. Patch AppRun so it sources the new hook before executing AppRun.wrapped
if [ -f "$appdir/AppRun.wrapped" ]; then
if ! grep -q "wayland-compat.sh" "$appdir/AppRun"; then
cat << 'EOF' > "$appdir/AppRun"
#!/usr/bin/env bash
HERE="$(dirname "$(readlink -f "${0}")")"
if [ -f "$HERE/apprun-hooks/wayland-compat.sh" ]; then
. "$HERE/apprun-hooks/wayland-compat.sh"
fi
exec "$HERE/AppRun.wrapped" "$@"
EOF
chmod +x "$appdir/AppRun"
fi
elif [ -f "$appdir/AppRun" ]; then
mv "$appdir/AppRun" "$appdir/AppRun.wrapped"
cat << 'EOF' > "$appdir/AppRun"
#!/usr/bin/env bash
HERE="$(dirname "$(readlink -f "${0}")")"
if [ -f "$HERE/apprun-hooks/wayland-compat.sh" ]; then
. "$HERE/apprun-hooks/wayland-compat.sh"
fi
exec "$HERE/AppRun.wrapped" "$@"
EOF
chmod +x "$appdir/AppRun"
fi
}
# 3. Repack AppDir into AppImage
repack_appdir() {
local appdir="$1"
local expected_appimage="$2"
local bundle_dir
bundle_dir=""
local appimage_base
appimage_base=""
echo "Repacking AppImage into $expected_appimage..."
(
cd "$bundle_dir"
export LDAI_OUTPUT="$appimage_base"
# Remove existing AppImage before repacking
[ -f "$expected_appimage" ] && rm -f "$expected_appimage"
if [ -n "$LINUXDEPLOY_BIN" ]; then
"$LINUXDEPLOY_BIN" --appdir "$appdir" --output appimage
elif command -v appimagetool >/dev/null 2>&1; then
appimagetool "$appdir" "$expected_appimage"
elif [ -x "$TEMP_BIN/linuxdeploy-plugin-appimage" ]; then
"$TEMP_BIN/linuxdeploy-plugin-appimage" --appdir "$appdir"
else
echo "Error: Could not find linuxdeploy or appimagetool to repack $appdir" >&2
exit 1
fi
)
echo "Successfully repacked AppImage at $expected_appimage"
}
# 4. Process targets
if [ "" != "" ]; then
TARGET_PATH=""
if [ -d "$TARGET_PATH" ]; then
patch_appdir "$TARGET_PATH"
bundle_dir=""
appdir_name=""
expected_appimage="/.AppImage"
repack_appdir "$TARGET_PATH" "$expected_appimage"
elif [ -f "$TARGET_PATH" ]; then
TEMP_EXTRACT=
echo "Extracting AppImage: $TARGET_PATH"
(cd "$TEMP_EXTRACT" && "$TARGET_PATH" --appimage-extract >/dev/null)
EXTRACTED_APPDIR="$TEMP_EXTRACT/squashfs-root"
patch_appdir "$EXTRACTED_APPDIR"
repack_appdir "$EXTRACTED_APPDIR" "$TARGET_PATH"
else
echo "Error: Target path not found: $TARGET_PATH" >&2
exit 1
fi
else
APPDIRS=()
while IFS= read -r -d '' dir; do
APPDIRS+=("$dir")
done <
if [ "" -eq 0 ]; then
echo "No *.AppDir found to patch. (Did you run tauri build?)"
exit 0
fi
for appdir in ""; do
patch_appdir "$appdir"
bundle_dir=""
appdir_name=""
expected_appimage="/.AppImage"
repack_appdir "$appdir" "$expected_appimage"
done
fi
echo "Wayland AppImage patching complete."
And Change a Little Thing in the Existing Workflow
Replace All tauri build Commands With tauri build && source src-tauri/scripts/patch-appimage-wayland.sh
if you are using vite then replace the tauri build command with tauri build && source src-tauri/scripts/patch-appimage-wayland.sh in the scripts section of package.json.
{
"name": "drawx",
"version": "0.8.5",
"type": "module",
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
},
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"typecheck": "tsc --noEmit",
"preview": "vite preview",
"tauri": "tauri",
"tauri:build": "tauri build && source src-tauri/scripts/patch-appimage-wayland.sh"
},
"dependencies": {
"@astryxdesign/cli": "^0.5.4",
"@astryxdesign/core": "^0.5.4",
"@astryxdesign/theme-matcha": "^0.5.4",
"@astryxdesign/theme-neutral": "^0.5.4",
"@astryxdesign/theme-stone": "^0.5.4",
"@astryxdesign/theme-y2k": "^0.5.4",
"@excalidraw/excalidraw": "^0.18.1",
"@fontsource-variable/inter": "^5.3.0",
"@fontsource-variable/jetbrains-mono": "^5.3.0",
"@hugeicons/core-free-icons": "^4.3.5",
"@hugeicons/react": "^1.1.10",
"@iconify/react": "^6.0.2",
"@phosphor-icons/react": "^2.1.10",
"@stylexjs/stylex": "^0.19.1",
"@tauri-apps/api": "^2.12.1",
"@tauri-apps/plugin-clipboard-manager": "^2.4.1",
"@tauri-apps/plugin-dialog": "^2.8.1",
"@tauri-apps/plugin-fs": "^2.6.0",
"@tauri-apps/plugin-log": "^2.10.0",
"@tauri-apps/plugin-opener": "^2.7.0",
"@tauri-apps/plugin-process": "^2.4.0",
"@tauri-apps/plugin-updater": "^2.13.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.53.0",
"radix-ui": "^1.7.0",
"react": "^19.3.0",
"react-dom": "^19.3.0",
"react-router-dom": "^7.18.4",
"tailwind-merge": "^3.7.0",
"tw-animate-css": "^1.4.0"
},
"devDependencies": {
"@biomejs/biome": "^2.5.15",
"@oxlint/plugins": "1.81.0",
"@tailwindcss/vite": "^4.3.3",
"@tauri-apps/cli": "^2.12.1",
"@types/node": "^26.6.4",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@vitejs/plugin-react": "^6.1.2",
"astryx": "^0.0.0",
"oxfmt": "^0.72.0",
"oxlint": "^1.87.0",
"typescript": "~7.0.2",
"vite": "^8.3.4",
"zustand": "^5.0.15"
},
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": "^12.10.1",
"onFail": "warn"
}
},
"packageManager": "[email protected]+sha512.ba40a37eb1a370d60fea8c4cf1d364c13bcccef518e98ad2bcee954f539d38da37458e58261a3fa55e06523450ea0ffff9f497b135be41f2c15c1642bacace6c",
"trustedDependencies": [
"@astryxdesign/cli",
"@astryxdesign/core"
],
"allowScripts": {
"@astryxdesign/cli": true,
"@astryxdesign/core": true
}
}
Referred blog for initial solution of the issue.