一句话
不是单一故障,是「nix-ld 缺 Electron 运行库(已在世代层独立证实)」+「gateway 僵尸态重启循环」+「drkonqi 自身崩溃制造噪音」叠加。与克隆操作无因果关系——崩溃比克隆结束晚 26 分钟。当时推断的「盘1 会原样复发」已在盘1 实际启动后否定(见文末)。
时间线(实测,全部可追溯)
| 时刻 | 事件 | 证据来源 |
|---|
| 13:31 – 13:43:57 | 克隆盘2→盘1,rsync 29.7 GB / 2,240,069 文件 | clone-disk1.log |
| 13:39:13 | 盘1 生成 gen48 | 盘1 loader/entries |
| 14:09:46 / 14:09:55 / 14:13:49 / 14:14:11 / 14:22:13 | Hermes 二进制 SIGILL ×5 | coredumpctl list |
| 14:22:17 | drkonqi 列 coredump,自身也 SIGABRT | 用户 journal |
| 14:22 – 14:26 | gateway「already owns this host」循环,restart counter → 29 | 用户 journal |
| 14:25:04 | configuration.nix 被改(补 nix-ld 库) | 文件 mtime |
| 14:25:58 | gen47 = fix-hermes-desktop-black-after-clone-nixos | profile link |
| 14:29:38 | 重启 | /proc/uptime 反推 |
| 14:32:32 | desktop 启动,其后 0 崩溃 | ps + journal |
逐条裁决:报告的 5 层根因
| 报告的判定 | 裁决 | 实测依据 |
|---|
层1:TMPDIR 残留 Windows 路径 C:\Users\cat\.hermes\tmp | 方向对,位置判错,且与本次崩溃无关 | ~/.hermes/.env:530 与 profiles/nixos-u533b-u751f/.env:526 都已是 /home/cat/.hermes/tmp。Windows 路径只残留在 profiles/win10-u533b-u751f/.env:526 → 该层不成立为本次病因,但是真隐患(切到 win10 profile 会踩,会在 $HOME 下建出 ~/C:\Users\... 垃圾目录)。已修(见文末) |
| 层2:node-pty 缺 C++ 编译链 | 事实成立,归因不成立 | gcc/gnumake/python3/pkg-config 确在 configuration.nix 第 180 行;但 desktop 跑的是预编译包(198 MB,mtime 10-06 22:56),不跑 npm ci → 与黑屏无因果 |
| 层3:nix-ld 缺 Electron 运行库 → SIGILL | 采信(已独立硬证实) | 逐世代对比 <system>/sw/share/nix-ld/lib:gen45/gen46 = 437 个库,缺 libGLX_mesa / libfontconfig / libgdk_pixbuf / libpulse;gen47 起 = 525 个,四个全在 |
| 层4:GPU 子进程初始化失败 | 现象采信,机制表述需修正 | Chromium/Electron 的 SIGILL 不是「跳到非法指令」,而是 IMMEDIATE_CRASH()(x86 的 ud2)——代码主动触发的 CHECK / LOG(FATAL) 自杀;缺库或 GPU 初始化失败只是可能的触发条件之一 |
| 层5:sandbox fallback 残留 + transient unit 残留 | 部分采信 / 部分不可证 | transient unit 确实失败且至今未清:drkonqi-coredump-launcher@… ×3 仍 failed;windows-sandbox-fallback.json 当前是 {"state":"ok"},当时旧值已无法回溯 |
| 「gateway 层有僵尸锁」 | 采信(日志实锤) | A gateway already owns this host … PID 1101 … its control socket has not answered 每 ~11 秒一次,restart counter is at 27…29 |
| 归因「因克隆而起」(重建标签写的是 after-clone-nixos) | 驳回 | 克隆 13:43:57 结束,崩溃 14:09:46 起,相隔 26 分钟;且崩溃所处的 gen46 建于 12:32(早于克隆)。无因果证据;真实触发点不可考——desktop 的 stderr 走了终端、没进 journal |
| 「libglvnd 不能单独工作」/「drkonqi 崩溃是噪音」 | 采信 | libglvnd 只是 dispatcher;实测 drkonqi-coredump-launcher 自身 SIGABRT ×6 |
报告漏掉的(当时新增,最要紧)
- 盘1 停在修复之前(当时判断:启动后会原样复发)—— 后经追平解决,见文末。这条后来被实际启动否证了:盘1 以旧的 437 库也能进桌面,说明缺库不是唯一触发条件。
- 启动窗口内时钟错了 8 小时。
date/timedatectl 正确,但 journal 与 who -b 记成 +8h,systemd 甚至显示 since 22:29:45; 7h left。 - 残留 Windows 路径的确切位置:不在 default profile,在
profiles/win10-u533b-u751f/.env:526。 - desktop 不参与 Nix 构建:git 安装目录下的预编译产物 ⇒「补编译链、重跑 npm ci」对它无效;真正作用面只有 nix-ld 库集与进程启动环境变量。
- 另一处未清失败单元:
app-trilium-notes@796a2c2a…service 仍 failed。
已验证有效的修复(按判据计)
| 动作 | 生效判据(实测) |
|---|
| nix-ld 补 mesa / libGL / libGLU / fontconfig / freetype / gdk-pixbuf / libuuid / libpulseaudio / openssl | 库数 437 → 525;四个关键库自 gen47 起存在 |
| 重启系统 | desktop 进程环境实测 NIX_LD_LIBRARY_PATH=/run/current-system/sw/share/nix-ld/lib;此后 0 崩溃 |
| gateway 侧处理 | 那次开机后 already owns this host = 0、Scheduled restart = 0 |
| sandbox fallback 重置 | 文件值为 {"state":"ok"} |
下次同类故障的判据顺序
coredumpctl list | grep -i Hermes —— 先拿信号与二进制路径。- 信号是 SIGILL ⇒ 直接判为 Chromium
IMMEDIATE_CRASH(主动自杀),别去找「非法指令」。 ls $(readlink /nix/var/nix/profiles/system-N-link)/sw/share/nix-ld/lib | wc -l —— 逐世代比库数,最快最硬(437 vs 525 一眼定案)。tr '\0' '\n' < /proc/<desktop 主进程>/environ | grep NIX_LD —— 看运行进程实际拿到什么,不看配置「应该」给什么。- drkonqi 自身的 SIGABRT 全是噪音,忽略。
遗留待办:已全部处理(2026-10-09 16:57)
| 待办 | 处置与判据 |
|---|
| 盘1 追平(同步 /etc/nixos + /nix,重建引导) | 已完成:盘1 现为 gen50(jmy71df5…),nix-ld 库数 525、nix.gc 已生效;与盘2 的 configuration.nix md5 完全一致(3d751275f650ce4c9af5d556ce2d4566)。 过程中踩到:盘1 root 一旦被以 ro 挂载(僚机的 /mnt/disk1),同一启动周期内无法再 rw 挂载 → 给盘1 写入前必须先停掉这对挂载。 |
清 profiles/win10-u533b-u751f/.env:526 的 Windows TMPDIR | 已改:TMPDIR=/home/cat/.hermes/tmp(锚点唯一、CRLF 未动、-3 字节);备份 backups/config-backups/env.bak-20261009-144207。 |
| 时钟 8 小时偏差 | 已定论:RTC 里存的是本地时间(Windows 的默认写法),Linux 当 UTC 读 → 开机瞬间 +8h(14:29 记成 22:29,算术吻合),NTP 随后校正。Linux 侧已自愈;根治要在 Windows 侧 reg add "HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /t REG_DWORD /d 1 /f,否则每次启动 Windows 后都会重现。 |
关于「克隆是否保真」的权限审计(2026-10-09 16:57)
问题:盘1 上从盘2 克隆来的目录,属主是否被改乱?
| 检查项 | 结果 |
|---|
/ 顶层属主权限(盘1 vs 盘2) | 18 项完全一致;3 项差异全是挂载态假象:boot(vfat 挂着 ⇒ fmask=0077 显 700;未挂 ⇒ 空目录 755)、proc/sys(虚拟 fs 555 vs 空目录 755) |
/home 下 root 属主条目数 | 盘1 129 vs 盘2 128,差的那一条是 Hermes 写的交接说明文件 ⇒ 克隆保真 |
| 那些 root 条目哪来的 | 不是克隆造成的——是先前以 root 跑脚本留下的(~/.hermes/cache/scratch/boot-entries-backup-*、~/www/mihomo/data/*、plasma look-and-feel 符号链等),克隆如实复制 |
| 统一处置 | chown -R cat:users 全部 root 属主条目:128 → 0;6 个关键路径以 cat 身份实测均可写 |
不该改的:/etc /nix /var /usr /root 本就应是 root:root(NixOS 正常布局)。
故意保留 root 的一处:盘2 底层那个真实的 /s500data 保持 root:root 755 —— 平时被 bind 盖住不可见;万一 bind 失败,root 属主能挡住 cat 的静默写入,正是设计要防的「同路径不同内容分叉」。
hermes手册.txt
Hermes 手册(max2-nixos)—— 出异常时怎么恢复使用
============================================================
本机 Hermes 形态速记:
· 安装方式 = 官方源码链(git):/home/cat/.hermes/hermes-agent
· 数据目录 HERMES_HOME = /home/cat/.hermes
· CLI 入口 = /home/cat/.hermes/hermes-agent/.hermes/bin/hermes (下文直接写 hermes)
· 两个长驻件:
桌面 = "hermes desktop"(Electron,预编译包 apps/desktop/release/linux-unpacked/)
网关 = systemd 用户单元 hermes-gateway.service(Telegram 等平台接入)
· 声明式设置(要 nixos-rebuild)在 /etc/nixos;本文件只讲「运行时不重建、如何把它救回来」
提示:agent 无 root,提权用 /run/wrappers/bin/sudo -n;脚本里命令一律写绝对路径。
============================================================
0. 黄金判据(先跑这三条,定位到下面哪一节)
============================================================
systemctl --user status hermes-gateway.service -n0 # 网关在不在
pgrep -af 'release/linux-unpacked/Hermes' # 桌面进程在不在
hermes logs desktop -n 40 # 桌面最近日志(黑屏/崩溃都看它)
============================================================
1. 【最常见】hermes desktop 出不来 / 黑屏 / 每分钟崩一次
============================================================
症状:
· 窗口黑屏、进不去 GUI;或
· 日志每 ~1 分钟一行 render-process-gone reason=crashed exitCode=132;或
· coredump 里是 SIGILL(信号4),故障点固定 Hermes+0x6e27995(ud2 = Chromium 主动自杀)。
根因(NixOS 特有):
预编译 Electron 的 chrome-sandbox 不是 setuid(NixOS 没法给 $HOME 里的文件加 setuid)
→ Chromium 沙箱起不来 → 应用降级 --no-sandbox,并把"降级结论"写进两个 sticky marker:
~/.config/Hermes/linux-gpu-fallback.json {"state":"fallback","reason":"gpu-launch-failure",...}
~/.config/Hermes/windows-sandbox-fallback.json {"state":"fallback","reason":"boot-loop",...}
marker 的 version 记成 0.0.0(永不等于真实版本)→ 永不重探。
判据:
cat ~/.config/Hermes/linux-gpu-fallback.json ~/.config/Hermes/windows-sandbox-fallback.json
grep ELECTRON_DISABLE_SANDBOX /home/cat/.hermes/.env # 应有:ELECTRON_DISABLE_SANDBOX=1
grep -c 'render-process-gone' /home/cat/.hermes/logs/desktop.log
恢复(让它"确定地不带沙箱"启动):
1) 若 .env 里没有这行,就把它追加到 /home/cat/.hermes/.env(只加这一行,别动别的):
ELECTRON_DISABLE_SANDBOX=1
2) 关掉残留桌面进程(安全做法:按 /proc 精确匹配,避免 pkill -f 把执行它的 shell 一起杀):
python3 - <<'PY'
import os,glob
pat=b'release/linux-unpacked/Hermes'; me=os.getpid()
for d in glob.glob('/proc/[0-9]*'):
pid=int(os.path.basename(d))
try:
if pat in open(d+'/cmdline','rb').read() and pid!=me: os.kill(pid,15)
except Exception: pass
PY
sleep 2; pgrep -af 'release/linux-unpacked/Hermes' || echo "已清空"
3) 重新拉起:
hermes desktop
4) 验收(三条都要数,等 3~5 分钟):
grep -c render-process-gone ~/.hermes/logs/desktop.log # 两次取样不增
/run/wrappers/bin/sudo -n dmesg | grep -c 'trap invalid opcode' # 期望 0
hermes logs desktop -n 20 | grep -E 'backend is ready|published connection=local'
注意:
· 别把这两个 marker 当敌人去删/改。它们记的是"崩溃结论";修法方向正是让 no-sandbox 成为固定条件
(.env 那一行)。只移 marker、不加 .env → 崩溃会回来。version=0.0.0 卡着不清是已知小坑,不影响修法。
· 日志里 "incorrect permissions on /dev/shm" 是假线索(/dev/shm 实测可写、size 约 30G)。
· 这条修法在本机 2026-10-13 14:25 才真正落到 .env,此后多时零崩溃 —— 初步有效,未到"根治保证"。
============================================================
2. desktop 起来的其它拦路(不是崩溃循环)
============================================================
2.1 后端没起(桌面白屏/转圈)
日志特征:Could not connect to Hermes gateway (WebSocket error before open) / ECONNREFUSED 127.0.0.1:<port>
处置:桌面在等它自己的本地 serve 后端。等 30s 重开;仍不行按第 1 节关进程再 hermes desktop。
hermes gateway status
2.2 应用页加载失败(黑窗口)
日志特征:Renderer failed to load: ERR_FAILED (-2) loading 'file://.../dist/index.html'
处置:桌面包损坏/半更新。先 hermes doctor --fix;再不行 hermes update 重装(桌面会重建)。
2.3 从无图形会话被拉起(直接退出)
日志特征:Missing X server or $DISPLAY → The platform failed to initialize. Exiting.
处置:必须在该桌面会话里跑 hermes desktop。要给别的上下文临时配显示变量,照抄正在跑的 plasmashell:
tr '\0' '\n' < /proc/$(pgrep -x plasmashell | head -1)/environ \
| grep -E 'DISPLAY|XAUTHORITY|DBUS_SESSION_BUS_ADDRESS|WAYLAND_DISPLAY'
============================================================
3. 网关(hermes-gateway.service)异常
============================================================
症状:日志刷 "A gateway already owns this host ... its control socket has not answered"(僵尸锁),
restart 计数一直涨;或 Telegram 收不到回复。
判据:
hermes gateway status
systemctl --user status hermes-gateway.service -n30
hermes logs gateway -n 50
恢复(按顺序):
hermes gateway restart # 首选
hermes gateway stop ; sleep 3 ; hermes gateway start # 停干净再起
hermes gateway migrate # 若一直刷僵尸锁:把各 profile 收敛到"一个主机网关"
hermes gateway list # 看每个 profile 的网关状态
============================================================
4. 启动即退、报缺库(nix-ld)
============================================================
症状:hermes desktop 立刻退出;报 /lib64/ld-linux-x86-64.so.2 不存在,或缺 libGLX/libfontconfig/libgdk_pixbuf/libpulse。
判据:
L=$(readlink -f /nix/var/nix/profiles/system)/sw/share/nix-ld/lib
ls "$L" | wc -l # 本机应约 525
ls "$L" | grep -E 'libGLX_mesa|libgdk_pixbuf|libpulse' # 关键库应在
修法:属于声明式——补 /etc/nixos 里 programs.nix-ld 的库列表后 nixos-rebuild switch(本文件不展开)。
提醒:这条治的是"启动即退/缺库",不要拿它解释"每分钟 SIGILL 崩溃"——那是第 1 节。
============================================================
5. config.yaml 损坏(改了配置没生效 / 直接报错)
============================================================
症状:日志 "Your settings file (...) has a formatting error at line N ... running on previous settings"。
处置:
hermes config check
hermes config edit
# 坏文件副本:~/.hermes/backups/config/config.yaml.corrupt.<时间戳>
# 回退: ls -t ~/.hermes/config.yaml.bak-* | head (取最近一份覆盖回去)
铁律:改配置一律用 hermes config set <key> <val>,别手改(缩进错 = 整个配置不生效)。
============================================================
6. 会话 / 数据库异常
============================================================
症状:报 "another process holds an old copy of the session database's write-ahead log",或某会话读不出。
处置:先关占用进程(网关 + 桌面)再重开;state.db 的 -wal/-shm 不要手删。
hermes sessions list
hermes sessions show <完整id> # id 形如 YYYYMMDD_HHMMSS_xxxxxx,别用截短前缀
============================================================
7. 全量备份 / 还原(重装或换机前的保命符)
============================================================
hermes backup -o "/s500data/软件数据备份/hermes备份/hermes-backup-$(date +%Y%m%d-%H%M%S).zip"
hermes import <zip> # 还原;还原前先给现状再备一份
不含代码与运行时(hermes-agent、tools、installs);还原后 hermes update 补齐。
============================================================
8. 应急刹车
============================================================
hermes pause # 暂停 cron / kanban 派发 / 新的网关回合
hermes resume # 解除
关桌面:见第 1 节的安全 kill 脚本。关网关:hermes gateway stop。
============================================================
9. 日志与诊断位置速查
============================================================
hermes logs <name> [-f] [-n N] # name: agent(默认) errors gateway gui desktop update handoff
/home/cat/.hermes/logs/ # 上述文件 + desktop-chromium.log(含 Missing X server / FATAL 等)
/home/cat/.config/Hermes/ # 桌面用户数据:Crashpad/(崩溃转储)、两个 *-fallback.json
coredumpctl list | grep -i Hermes ; coredumpctl info <pid>
/run/wrappers/bin/sudo -n dmesg | grep -iE 'trap invalid opcode|segfault'
hermes doctor ; hermes doctor --fix ; hermes doctor --live
============================================================
10. 一句话对照:三种"桌面坏"别互相套错
============================================================
· 启动即退 / 报缺 .so → 第 4 节 nix-ld(声明式补库 + rebuild)
· 黑屏 + 每分钟 SIGILL 崩溃 → 第 1 节 沙箱降级 marker(.env ELECTRON_DISABLE_SANDBOX=1)
· 白屏 / 连不上后端 → 第 2.1 后端未就绪(等待或重启网关)
(手册日期 2026-10-13;与 nixos 台账 docs/hermes-desktop-crash-diagnosis.md 同源。)