Fix Blank Tauri Windows on Linux: Clear the Fontconfig Cache
· 5 min read · 824 words
Two of my Tauri apps, MeetPoise and ThinkUtils (source), stopped working on my Linux machine. Their windows came up blank or never appeared. The fix had nothing to do with either app:
find ~/.cache/fontconfig -type l | wc -l # anything above 0 means you are affected
mv ~/.cache/fontconfig ~/.cache/fontconfig.bak-$(date +%Y%m%d)
fc-cache -f
Restart the app afterwards. The rest of this note explains how I got there, because nearly every fix suggested for this symptom is wrong for this cause.
Symptoms
- The app process starts, along with
WebKitNetworkProcessandWebKitWebProcess, but the window stays blank or white, or never appears. WebKitWebProcessuses 100% CPU on its main thread and never loads the page or runs any JavaScript.- On exit, the log prints
WebProcess didn't exit as expected after the UI process connection was closed. - The usual WebKitGTK workarounds do nothing:
WEBKIT_DISABLE_DMABUF_RENDERER=1,WEBKIT_DISABLE_COMPOSITING_MODE=1,GDK_BACKEND=x11,WEBKIT_SKIA_ENABLE_CPU_RENDERING=1, and turning off the sandbox. Wayland and the NVIDIA driver were not the cause.
Tauri renders through WebKitGTK on Linux, so anything that breaks WebKitGTK breaks every Tauri app on the machine at once. That is the first useful clue: when unrelated Tauri apps fail together, look below the app.
Root cause
strace -f on the launcher showed that the web process's last syscalls were reads of files in ~/.cache/fontconfig. After that it made no more syscalls and spun at 100% CPU. It was stuck in font handling before it had loaded any page.
Two experiments isolated the cause:
- With the same system config (
/etc/fonts/fonts.conf) pointed at a fresh, empty cache directory, WebKit loaded the page and ran JavaScript. With the existing cache, it hung. - Each user font folder (
~/.fonts/*,~/.local/share/fonts/*) worked fine on its own. The fonts were fine. The cache was the problem.
The cache held hundreds of symlinks named <hash>-le64.cache-9, cache-10, and cache-11, all pointing to <hash>-le64.cache-12 files. Every one was dated the same day my apps started failing.
What wrote those symlinks: Chrome 154's bundled fontconfig
Chrome 154 (and Brave 1.96.59, built on the same Chromium) ships its own, newer fontconfig. That copy writes cache-12 files and then adds older-format names that link to them. The system fontconfig reads cache-9, follows the link, and parses a format-12 file as if it were format 9. WebKitGTK then loops forever, and KDE Plasma and Qt6 apps crash with SIGSEGV in FcCharSetHasChar.
- Chromium: issue 565132857 and issue 565475896
- Brave: brave-browser#59349
- fontconfig upstream, where the real fix is still open: work item 565
Newer builds stop writing the links. According to the Brave tracker, Chromium 154.0.8037.98 removed HAVE_SYMLINK from the bundled fontconfig's build config, so the alias code is compiled out. That is a build-flag workaround, not a code fix, and the upstream logic is unchanged. More importantly, upgrading the browser does not remove links that were already written. You have to clear the cache once by hand, which is why the browser update alone did not fix my apps.
Fix
mv ~/.cache/fontconfig ~/.cache/fontconfig.bak-$(date +%Y%m%d) # or: rm -rf ~/.cache/fontconfig
fc-cache -f
Then restart the affected app. Delete the backup once everything works. If it comes back, run the find check from the top of this note and repeat the fix.
Check that WebKitGTK works
This script loads one line of HTML in a bare WebKitGTK view and reports whether the JavaScript ran:
cat > /tmp/wk.py <<'EOF'
import gi
gi.require_version('Gtk','3.0'); gi.require_version('WebKit2','4.1')
from gi.repository import Gtk, WebKit2, GLib
w = Gtk.Window(); v = WebKit2.WebView(); w.add(v)
v.connect("load-changed", lambda v, e: print("LOAD", e.value_nick, flush=True))
v.load_html("<script>document.title='JSOK'</script>", "about:blank")
GLib.timeout_add(6000, lambda: (print("TITLE", v.get_title()), Gtk.main_quit()))
w.show_all(); Gtk.main()
EOF
timeout 20 /usr/bin/python3 -I /tmp/wk.py
- Healthy:
LOAD started,committed,finished, thenTITLE JSOK. - Broken: only
TITLE None.
Use the system /usr/bin/python3. A conda Python has no gi module, and its bundled libraries can break GTK on their own.
To confirm the cache is the culprit before deleting anything, run the same test against a fresh cache directory. If this passes while the plain run fails, the cache is the problem:
sed -e 's#<cachedir prefix="xdg">fontconfig</cachedir>#<cachedir prefix="xdg">fontconfig-fresh</cachedir>#' \
-e 's#<include ignore_missing="yes">conf.d</include>#<include ignore_missing="yes">/etc/fonts/conf.d</include>#' \
/etc/fonts/fonts.conf > /tmp/fresh.conf
FONTCONFIG_FILE=/tmp/fresh.conf timeout 40 /usr/bin/python3 -I /tmp/wk.py
Debugging gotchas
pkill -f <pattern>also matches the shell that runs it. Usepkill -x <name>to kill the app by its exact process name.- With
ptrace_scope=1andperf_event_paranoid=4, gdb and perf cannot attach to the web process. Runstrace -fon the launcher instead and let it follow the children.
Keep reading
- Make Your CI Actually Launch Your Linux Desktop App
A Flatpak build that passed every structural check and still died one line into launch. Why green CI proved nothing about the GUI, and how to install the real artifact and start it under Xvfb instead.
