故障排查
同步、配对、剪贴板权限、日志收集与紧急重置的处理路径。
UniClipboard 的故障可以按层定位:守护进程是否在跑 → 配对是否成立 → 对端是否被发现 → 传输是否打通 → 表示是否落地。下面按这个顺序展开,每节都写明"看哪些信号"和"动哪些命令"。
在排查任何问题之前,先在两端各跑一遍 uniclip status 与 uniclip members 拿到客观状态。
人脑记忆里的"应该在线"经常和实际不符。
先看这里:30 秒分流
| 现象 | 多半的层次 | 跳到这一节 |
|---|---|---|
| 命令报"daemon not running" | 守护进程 | 守护进程 |
join <code> 报错 / 一直等待 | 配对 | 配对失败 |
双方都在线但 members 看不到对方 | 发现 | 对端不上线 |
| 能看到对方但同步慢、文件传不动 | 传输 | 卡在中继 / 同步缓慢 |
| 复制了但对端啥也没收到 | 剪贴板权限 | 剪贴板权限 |
| 搜索结果空 / 报"index not ready" | 全文索引 | 搜索与索引 |
| 手机连不上桌面 / 401 / 图片损坏 | 移动端同步 | 移动端同步(iOS 快捷指令) |
守护进程
CLI 的所有同步功能都依赖守护进程。uniclip start 拉起、uniclip stop 停掉、uniclip status 看健康度。
uniclip status # 摘要
uniclip status --json # 字段稳定,方便比对关键字段:
daemon.running—— 进程是否存活。space.bound—— 当前 profile 是否已绑定到某个空间。false说明还没init或join。network.endpoint—— 本机 iroh node ID。换 Wi-Fi 不会变,变了说明换了 profile 或 keyslot。network.relay—— 当前选用的中继域名;null说明走的是直连。peers[].reachability—— 对每个已配对设备的可达性快照。membership_convergence—— 当前空间是否已完全连接,可能为complete、converging、waiting_for_upgrade或blocked。
如果 daemon.running = false 但 uniclip start 又秒退,先用前台模式抓栈:
uniclip start --foreground -v常见原因是 keyslot 文件被另一份进程占着(典型场景:GUI 与 uniclip 用了同一个默认 profile 同时跑)。在 CLI 端加 --profile dev 让二者分家即可。
守护进程日志里出现 "System secure storage probe failed; falling back to file-based KEK"
这条 WARN 说明守护进程启动时够不到 freedesktop Secret Service(GNOME Keyring / KWallet)。守护进程不会因此崩,只是 Key Encryption Key 落到了应用数据目录的文件里,而不是系统钥匙串。常见两种触发场景:
Snap 沙箱 —— AppArmor 拒绝了 D-Bus 调用,原因是 password-manager-service plug 没接上。接上它就能把 KEK 搬回系统钥匙串:
sudo snap connect uniclipboard:password-manager-service
# 接好之后重启应用极简 Wayland 会话(hyprland / sway 等) —— 会话看起来像桌面(DISPLAY 和 DBUS_SESSION_BUS_ADDRESS 都有),守护进程于是尝试系统钥匙串,但实际没有运行 secret service —— 或者跑着却处于锁定状态、又没有解锁 prompter。探测有一个短超时兜底,所以守护进程会在几秒后降级到文件式 KEK,而不是卡死。想继续用系统钥匙串,就在会话里跑一个已解锁的 secret service,例如:
gnome-keyring-daemon --start --components=secrets
# 更好的做法:用 pam_gnome_keyring 在登录时自动解锁,
# 或在 KeePassXC 里开启 "Secret Service Integration"更早的版本遇到同样情况会卡住或直接 Daemon startup/probe failed during Tauri bootstrap 崩溃。当前版本会改为降级到文件式 KEK;这时无论接 snap plug 还是起 secret service,都只决定 KEK 存在哪里,不再决定守护进程能不能起。
配对失败
邀请码报"invalid or expired"
邀请码 短期、一次性。一旦过期或已被消费,就需要在 sponsor 上重新生成:
uniclip invite # 在 sponsor 上重出一张不要把邀请码当长效凭据保存或粘到聊天群里 —— 它的设计就是只活到下一次握手。
输入正确的邀请码,握手却卡住
握手会跑 PAKE 校验口令。如果对方在 members 里始终不出现:
-
确认两端的系统时间偏差小于几分钟。Argon2id 与签名校验对时间漂移敏感。
-
在 sponsor 端
uniclip status --json | grep handshake查看是否在等 joiner,如果根本没收到说明发现层就没打通,跳到对端不上线。 -
默认握手 TTL 约 3 分钟。超时后 sponsor 会丢弃这次邀请,joiner 拿到的就是"invitation expired"。重新
invite即可。 -
sponsor 端跑着 Tailscale 之类的 overlay 网络? 默认情况下 Tailscale CGNAT (
100.64.0.0/10) 与 IPv6 ULA (fd7a:115c:a1e0::/48) 地址不会被写进邀请,joiner 拿到的全是不可达的 LAN 地址就会一直拨不通。在 sponsor 端 设置 → 网络 → 允许覆盖网络地址 打开并重启 daemon,Tailscale 地址才会进入邀请。Clash TUN 的 fake-ip (198.18.0.0/15) 与 IPv4 link-local (169.254.0.0/16) 始终被过滤、无开关 —— 这类网卡本来就不能拿来真实拨号,让 UniClipboard 走真实物理网卡即可。这个开关只影响桌面 ↔ 桌面 pairing。移动端同步有自己的「监听 IP」下拉(配置 modal / 设备卡片 dialog),它 始终 会列出 Tailscale CGNAT 网卡,与「允许覆盖网络地址」无关 —— 移动端配对是人工挑选的,所以即使这个开关关着,Tailscale 可达的手机也能正常配对。
"passphrase mismatch" / 加入后立刻被踢
口令错误会让密钥重新封装失败。这是设计行为,不是 bug —— sponsor 永远看不到错误的口令明文。校对口令再来一次就好。
口令一旦丢失就 无法找回。这是 Argon2id + PAKE 的代价:服务器侧没有任何能解密的副本。 这种情况下唯一的恢复路径是在还能登录的设备上吊销丢失设备、或彻底重建空间。
对端不上线
发现层并行跑三种查找:mDNS、rendezvous、直连地址缓存。任何一种命中都算。如果 members 里看不到对端:
同 Wi-Fi?先排除 AP 隔离
许多家用路由器和咖啡馆 Wi-Fi 默认开启 client isolation / AP isolation,会丢弃同一 SSID 内设备之间的 mDNS 与单播流量。
- 路由器后台找一下 "AP Isolation"、"Client Isolation"、"无线隔离"、"访客网络" 等词,关掉。
- 来宾网络通常永久开着隔离,把两台机器都接到主网络再试。
跨网络?确认 rendezvous 可达
跨家庭网络、手机热点、4G/5G 的发现依赖 rendezvous(HTTPS)。如果你在严格的企业网络下,可能整个 HTTPS 出站都被中间盒拦了。
- 临时换到手机热点验证一下;只要热点下能发现,问题就锁定在原网络的出站策略上。
- 防火墙白名单需要放开 iroh 默认的 rendezvous + 中继域名。具体域名见
uniclip status --json的network字段。
双方时钟偏差?
签名地址记录会带时间戳。如果一端时钟漂移超过几分钟,地址记录会被另一端当过期丢掉,结果就是"看似在线,谁都找不到谁"。
卡在中继 / 同步缓慢
uniclip status 里 network.relay 非空就说明走的是中继 —— 能跑,但延迟和带宽都不如直连。如果你确定双方在同一个网络下却仍然走中继:
- 对称 NAT。 部分运营商 / 移动网络下 NAT 端口分配不可预测,打洞会失败。换网络(或开 IPv6)通常立刻好。
- IPv6 被禁。 路径上某一跳关掉了 IPv6 时直连会回退到 IPv4 NAT 打洞。
- 企业网络。 出站 UDP 全封的环境只能走中继,且某些网络会进一步把中继也封掉,那种情况下 UniClipboard 在该网络就是不可用。
- 本机代理在转发 relay 流量。 海外 relay + 本机开梯子时,默认规则常常把 relay 域名也走代理,导致带宽被代理出口压住、UDP/QUIC 兼容性变差。让 relay 域名走 DIRECT,详见 自建 iroh relay — 本机有梯子时让 relay 走直连。
中继看到的永远是密文。中继可用性影响的是 性能 与 可达性,不影响机密性。详见 配对与同步 — 传输。
文件类负载走的是分块 blob 协议(见 同步内容 — 大负载),中途断网 / 唤醒后会续传。如果一个大文件 几小时 还在零星传,多半是某一块卡住没重试 —— 在发送端 uniclip stop && uniclip start 通常能踢一脚。
剪贴板权限
复制后对端没动静、uniclip watch 也没事件,往往是本机根本没读到剪贴板。
已录制的全局快捷面板快捷键需要 输入监控(Input Monitoring) 权限。请在 系统设置 → 隐私与安全性 → 输入监控 中授权,然后完全退出并重新启动应用。
可选的双击修饰键触发方式使用另一项独立的 辅助功能(Accessibility) 权限。UniClipboard 只会静默检查,权限不可用时会禁用下拉框。点击旁边的 打开辅助功能设置;如果列表里没有 UniClipboard,点 + 手动加入 /Applications/UniClipboard.app,授权后返回应用。剪贴板捕获本身不依赖辅助功能权限。
Windows 通常不需要额外授权。如果 uniclip watch 没事件:
- 杀软或 EDR 可能把
UniClipboard.exe/uniclip.exe拦住了剪贴板钩子。检查事件日志或杀软隔离区。 - 远程桌面会话内的剪贴板独立于宿主,关掉 RDP 剪贴板重定向再试。
桌面会话差异最大:
- Wayland:原生支持
ext-data-control-v1(GNOME / mutter ≥ 47、Plasma 6)与wlr-data-control(Sway / Hyprland 等 wlroots 系合成器),无需安装桥接工具。两个协议都不可用时会自动回落到 XWayland(X11 路径)。 - X11:开箱即用,内置原生剪贴板监听,不依赖
xclip/xsel等外部剪贴板工具。 - 无头服务器:没有 X / Wayland 时只剩 CLI 的
send/watch工作;GUI 的剪贴板捕获不可用。
搜索与索引
uniclip search status 报告全文索引状态。
uniclip search status # ready / building / missing
uniclip search rebuild # 同步重建(会阻塞直至完成)常见情况:
- "index not ready" —— 守护进程刚启动 / 大版本升级后正在重建。
status会给出进度。 - 重建后仍然查不到旧条目 —— 旧条目可能在升级时已经被保留策略 GC。
uniclip dev dump-clipboard --limit N(隐藏命令)可以核对历史是否真的还在。 - 索引文件损坏(罕见) —— 进程在写索引时被 SIGKILL 等极端场景。删除数据目录下的索引子目录,再
uniclip search rebuild即可;剪贴历史本身是分开存的,不会丢。
移动端同步(iOS 快捷指令)
移动端伴侣走的是 LAN 上的明文 HTTP + Basic Auth,与 iroh 对端网络完全 独立。常见问题大致是这几类。
手机打不开 URL
现象:点击安装 URL 或运行快捷指令直接超时,连 401 / 4xx 都没有。
- 手机能拨通你宣告的地址吗? 默认部署下手机和桌面要在同一 Wi-Fi / 子网;如果你用了 server 节点(公网 HTTPS)或 Tailscale / VPN,确认手机 走的就是那条通道。移动端本身不走中继、不打洞。
- 对外宣告的 IP 必须是手机能拨通的。 桌面 socket 永远 bind 在
0.0.0.0,但安装 URL 里嵌的 IP 必须是手机能够拨通的真实 LAN IPv4。Configure dialog 已经替你兜住这一点:监听 IP 为Auto时, 「当前监听地址」行会内联展开列出全部 RFC1918 候选 —— 挑手机所在 那个直接复制;选了具体网卡时,行内就是固定的那条 URL。CLI 走uniclip mobile network set --ip <LAN_IPV4>。 - 看监听器状态。
uniclip mobile status在 daemon 试图 bind 但 失败时会上抛lan_listener_error(端口被占、权限不足等),先解决 底层错误或换一个端口。 - 桌面操作系统的防火墙。 确认
42720(或你自定义的端口)允许 LAN 入站。 - 最近改过 IP / 端口吗? 监听器配置变了需要重启 daemon 才会生效;
手机端快捷指令里的
url字段也得跟着更新。
401 Unauthorized
用户名或密码错了。原因有两类:
- 明文密码在注册时 只显示一次。丢了只能在设备行点 轮换密码
(或
uniclip mobile revoke <id>+add)—— 没办法 把原始密码再拿回来。 - 轮换之后,手机上的快捷指令里可能还存着旧凭据。把
url/username/password字段都更新一次。
iPhone 上传的图片看起来损坏或显示为空白
桌面端会嗅探上传字节的 magic 头来还原正确的 image/* MIME(iOS
快捷指令经常把所有上传都标成 application/octet-stream,不看扩展名)。
这套嗅探在 0.7.0-alpha.6 落地;如果 JPEG / PNG 粘贴成空白或非法图片,
先用 uniclip --version 确认版本,然后 升级到 0.7.0-alpha.6 或更新。
公共 Wi-Fi
不要 在咖啡馆 / 机场 / 会场的公共 Wi-Fi 下开启 LAN 监听器。v1
线上格式是明文 HTTP + Basic Auth —— 同一 SSID 上的人就能嗅到你的剪贴
内容。临时需要在不可信网络上工作时,先
uniclip mobile network off 关掉监听器,回到可信网络再开。
改了 LAN IP 或端口之后?
新值生效需要两件事:
- 重启 daemon,让监听器重新 bind。
- 把手机端快捷指令里的
url字段改成新的对外宣告 URL。
uniclip mobile status 可以快速确认 daemon 当前宣告的是哪个。
收集日志
给 issue 报告收齐材料最快的方式是用内置导出:它会把最近 24 小时的 GUI、daemon、CLI 日志打成一个 zip 放到下载目录。
- GUI: 设置 → 常规 → 导出日志。
- CLI:
uniclip debug export-logs(用--since-hours <N>放宽或 收窄时间窗口)。
如果问题很难复现,先开启更详细的日志(设置 → 常规 → 调试模式,或
uniclip debug on),复现后再导出。事后记得关掉并重启。
如果你更想手动拿文件,日志写在各平台约定的日志目录下(已和加密历史分开存放)。每种进程只保留最近 7 天,更早的会在启动时自动清理:
| 平台 | 路径 |
|---|---|
| macOS | ~/Library/Logs/app.uniclipboard.desktop/ |
| Linux | ~/.local/state/app.uniclipboard.desktop/logs/ |
| Windows | %LOCALAPPDATA%\app.uniclipboard.desktop\logs\ |
每种进程各写各的文件:uniclipboard-gui、uniclipboard-daemon、uniclipboard-cli。带 UC_PROFILE 时目录后会有后缀(如 app.uniclipboard.desktop-dev)。详见 安装 — 数据存储位置。
复现一次问题再抓日志,效果远好于事后翻:
# 前台跑守护进程,把 debug 级别日志直接输出到终端
uniclip stop
uniclip start --foreground -v提交 issue 时请尽量附上:
uniclip --version、操作系统与版本。uniclip status --json(两端各一份)。- 复现步骤与时间戳,对应时间窗口的日志切片即可,不必整份上传。
- 不要 把数据库文件、邀请码、空间口令贴到 issue 里。
紧急重置(最后手段)
下面这些操作 会丢失本地剪贴历史,且无法回滚。仅在前面所有步骤都没解决问题时使用。
如果应用已经走到了锁屏页(要求输入口令),但你忘了口令,这种情况下不需要走 CLI:
- 在锁屏页点击 「忘记口令?重置并重新开始」。这个链接在页面底部, 口令 modal 弹出时内部也有一个相同的入口。
- 在二次确认对话框里输入
RESET,然后点 重置。 - 应用会删掉本机磁盘上的 keyslot 与 KEK、清空
SetupStatus,并把你 送回 setup 页。之后可以重新init一个新空间或从另一台设备join。
这与下面 CLI 标签页里的操作是同一个破坏性动作 —— 执行后本机历史无法 找回。空间里其他设备不受影响(参见下方提示)。
uniclip stop
# 然后删除该 profile 的数据目录(路径见上文)
# Linux 示例:
rm -rf ~/.local/share/app.uniclipboard.desktop清理后 uniclip init 或 uniclip join 即可重来。系统密钥环里的 KEK 条目也会在下次 init 时被覆盖。
- 退出 GUI,
uniclip stop。 - 卸载安装包:
- macOS Homebrew:
brew uninstall --cask uniclipboard && brew uninstall uniclipboard - Windows:设置 → 应用 → UniClipboard → 卸载(或控制面板 → 程序与功能)
- Linux Snap:
sudo snap remove uniclipboard - Linux COPR (dnf):
sudo dnf remove uniclipboard && sudo dnf copr disable mkdir700/uniclipboard-alpha - Linux .deb:
sudo apt remove uniclipboard - Linux .rpm(手动装的):
sudo dnf remove uniclipboard - AppImage:直接删
.AppImage文件即可。
- macOS Homebrew:
- 删除数据目录(同上)。
- 手动 清理系统密钥环条目:
- macOS Keychain:搜
uniclipboard,删条目。 - Windows Credential Manager:控制面板 → 用户账户 → 凭据管理器 → Windows 凭据,删
uniclipboard:*。 - Linux Secret Service:用
seahorse或secret-tool清掉uniclipboardnamespace。
- macOS Keychain:搜
其它设备上的历史不受本机重置影响。如果是想让一台设备从空间里 消失,请在另一台还在线的设备上吊销它,而不是只在本机删数据 —— 仅删本机不会撤销 node ID 的可信状态。
还是没解决?
- 翻一遍 常见问题(FAQ) —— 很多"故障"其实是行为差异,不是 bug。
- 仍然不对劲就提 issue:github.com/UniClipboard/UniClipboard/issues。请遵循上面的"收集日志"清单。
- 安全相关问题请走 SECURITY.md 里给出的私有披露渠道,不要 直接开 public issue。