Linux 上 Electron/Chromium 应用所有文字不显示(图标正常):fontconfig 缓存混代问题

30 秒版:如果某个 Electron/Chromium 套壳应用的中英文文字全部消失,但图标、图片、色块正常,试试这两条命令:

bash 复制代码
find ~/.cache/fontconfig -name '*.cache-9' -type l | head   # 有输出 → 就是这个问题
fc-cache -f                                                  # 修复,然后重启应用

环境:Debian forky/sid,KDE Plasma 6.7.4(Wayland)。2026-11-01。

症状

  • CodeBuddy(Electron 37 / Chromium 138):整个界面只剩图标、色块、按钮底色,
    所有文字消失;
  • 微信 Linux 版 4.1.1.7(小程序/内嵌页走 Chromium 126):Qt 主界面完全正常,
    直播窗口等没有文字------看到的"emoji"是微信贴图,不走字体渲染。

同一台机器上,这些全部正常:Edge Dev 158、chromium-browser-unstable 155、

QQ(Electron 40 / Chromium 144)、官方 electron-quick-start(Electron 45)。

排除掉的方向(都是常规嫌疑,逐一验证无罪):

  • 不缺字体:fc-match 'sans-serif:lang=zh-cn' → Noto Sans CJK SC,在册 2622 个;
  • 字体文件不坏:Chromium 155 用同一套字体渲染中英文完好;
  • 不是动态库问题:所有应用的 ldd 显示链接的是同一套系统 freetype/fontconfig/harfbuzz;
  • 用户 fontconfig 配置、ld.so.preload、环境变量、GPU 驱动均无异常。

把正常/异常按引擎版本排开,边界一刀切齐:

应用 引擎 文字
Edge Dev Chromium 158 ✅
chromium-browser-unstable Chromium 155 ✅
electron-quick-start Electron 45(Chromium 14x) ✅
QQ Electron 40(Chromium 144) ✅
CodeBuddy Electron 37(Chromium 138) ❌
微信小程序壳 Chromium 126 ❌

Chromium ≤138 全灭,≥144 全活。

分析

用 CDP(--remote-debugging-port)连进中招应用的渲染进程,在 canvas 上量各字体族的

文字前进宽度:

复制代码
sans-serif  => w=0        ← 通用族名:解析归零
serif       => w=0
monospace   => w=0
cursive     => w=0
system-ui   => w=187.4    ← 正常
Noto Sans   => w=187.4    ← 正常
DejaVu Sans => w=194.1    ← 正常

通用族名(generic family)全部解析失败,具名字体全部正常。 这解释了症状的

"全有或全无":网页 CSS 几乎都写 font-family: sans-serif 或

-apple-system, "Segoe UI", sans-serif(Linux 上最终落到通用族名),所以整页文字消失;

图标、图片、SVG、贴图不走字体栈,照常显示。

遂成功复现(五行文字,三行走通用族名、两行走具名字体):

~/.cache/fontconfig 里堆了五代缓存文件:

复制代码
xxx-le64.cache-7     真实文件(远古)
xxx-le64.cache-9  -> xxx-le64.cache-12   ← 符号链接(毒点)
xxx-le64.cache-10 -> xxx-le64.cache-12   ← 符号链接(无害)
xxx-le64.cache-11 -> xxx-le64.cache-12   ← 符号链接(无害)
xxx-le64.cache-12    真实文件

每个缓存文件头 4 字节记录格式版本号。系统 fontconfig 2.17.1 只生成/读取 v9;

v12 是 Chromium 155 静态打包的一份更新版 fontconfig 写的,它同时留下上述

"兼容符号链接"。时间线吻合:

复制代码
2026-09-12 08:20:36   dpkg:chromium-browser-unstable 153 → 155
2026-09-12 08:21      cache-12 与兼容符号链接首次落盘

新版 fontconfig 的兼容设计是:v12 格式保持向前兼容(上游 fccache.c:

"ignore unknown object type for upper-compatible in the future"),旧版号的符号链接

指向新文件后,较老的 fontconfig 跟链接读 v12 也能解析。这个承诺对本机系统

2.17.1 完全成立------所以 fc-match、fc-list 乃至 fc-cat 反编译对比,

在毒缓存和干净缓存下输出逐字节一致,命令行层面看不出任何异常。

坏在 CodeBuddy / 微信把一份比"兼容链接"特性还老的 fontconfig 静态打包进了二进制:

它按 cache-9 文件名打开 → 跟链接读到 v12 字节 → 解析失败 → 该字体目录记录归零。

每个目录都中招,通用族名解析出的候选列表就空了。

三个条件:

  1. 受影响应用打包的 fontconfig 太旧,读不懂 v12;
  2. 机器上有更新版 fontconfig 的写入者(Chromium 155),把共享缓存升级并留下兼容链接;
  3. 两者共享同一个 ~/.cache/fontconfig。

对照组:QQ(Electron 40)正常------其内置 fontconfig 够新;Electron 45 撞同一份毒缓存

也安然无恙(w=178.9),甚至会顺手把毒链接重写回真实文件------"重启几次自己好了"

的玄学即来源于此。

进行测试:

缓存树形态 使用 Electron 37 测试
42×v12 + SYM-9→v12(Chromium 155 刚写完) w=0 ❌
42×v12 + 42×v9 真实文件,无 SYM-9 w=178.9 ✅
仅 1 个目录 v12+毒链接,其余 v9 w=178.9 ✅(单目录毒不翻全局)

结论:v9 与 v12 可以共存(上游设计如此,实测稳定);毒的不是"存在 v12 文件",

而是且仅是 cache-9 被符号链接指向了老读取器看不懂的字节。

为什么缓存会五代同堂不清理?每个写入者只按自己的版本号拼文件名、管自己的文件......

fc-cache -f / -r 都不扫描不删除其他版本的文件(实测植入 cache-7/12 后重跑,一个不删)。

解决

首选(外科手术)------把 cache-9 从毒链接改写回真实 v9 文件,不碰 v12,Chromium 155

的缓存继续有效:

bash 复制代码
fc-cache -f

或使用核选项------整个删除,按需重建:

bash 复制代码
rm -rf ~/.cache/fontconfig && fc-cache -f

重启受影响应用即可看到文字恢复。

修复后的混合态(真实 v9 + 真实 v12 + cache-10/11 链接)是稳定的:Chromium 155

重启不会破坏它,双方互认"未过期"。但 Chromium 155 重扫某字体目录时(字体文件

增删改、mtime 变化),会给该目录重建 SYM-9→v12,表现为零星复发。

3 分钟自检

bash 复制代码
# 1. 缓存目录有没有混代(正常应该只有一种版本号)
ls ~/.cache/fontconfig | sed 's/.*cache-//' | sort | uniq -c
# 2. 关键判据:cache-9 是不是符号链接?(cache-10/11 是链接无所谓,cache-9 才是毒)
find ~/.cache/fontconfig -name '*.cache-9' -type l | head
# 3. 有输出 → 修复
fc-cache -f
# 4. 重启应用