Skip to content

[Bug]: 键树渲染 zset 类型徽章时整个应用崩溃(gpui text.rs:650 unwrap on None) #416

Closed

Description

@shenfeng-1

发生了什么?/ What happened?

Redis 连接里只要出现 zset 类型的 key,键树渲染时整个应用直接崩溃(SIGABRT),没有任何提示或错误弹窗。

崩溃发生在渲染 zset 的类型徽章 Z 时:GPUI 对一个从未 measure 过的文本元素调用了 prepaint,TextLayout::prepaint 里的 unwrap() 撞到 None → panic。因为 release 是 panic = "abort"(Cargo.toml:315),整个进程直接 abort。

同一会话里稳定复现,崩了 9 次(~/Library/Logs/DiagnosticReports/navop-*.ips)。

如何复现?/ How can we reproduce it?

  1. 准备一个含 zset 键的 Redis(本例是 3 节点集群里的一台,但键树徽章的渲染与集群无关)
  2. 连接它,展开 db0,让键树渲染出 zset 键
  3. 应用崩溃

版本与系统 / Version and system

Navop 0.20.2(当前最新 release),macOS 27.0 / Apple Silicon (arm64)

截图、日志或其他信息 / Screenshots, logs, or anything else

从终端以 RUST_BACKTRACE=full 启动二进制复现,拿到的 panic 原文:

thread 'main' (70166448) panicked at /Users/runner/.cargo/git/checkouts/gpui-fast-1838033cdf77ee57/63b49b6/gpui/src/elements/text.rs:650:14:
called `Result::unwrap()` on an `Err` value: measurement has not been performed on Z

(backtrace 每一帧都是 __mh_execute_header,符号被 strip 了)

对应源码(gpui-fast @ 63b49b6,gpui/src/elements/text.rs:645-652):

fn prepaint(&self, bounds: Bounds<Pixels>, text: &str) {
    let mut element_state = self.0.borrow_mut();
    let element_state = element_state
        .as_mut()
        .with_context(|| format!("measurement has not been performed on {text}"))
        .unwrap();          // ← 650:14,这里 panic
    element_state.bounds = Some(bounds);
}

panic 信息里的 Z 就是 zset 徽章的文字,来自 crates/redis_view/src/redis_tree_view.rs:2027:

RedisKeyType::ZSet => ("Z", gpui::hsla(0.75, 0.6, 0.55, 1.0)),   // 紫色

渲染在 crates/redis_view/src/redis_tree_view.rs:2412-2426:

.when_some(key_type_badge, |this, (badge_text, badge_color)| {
    this.child(
        div()
            .w(px(18.0))
            .h(px(18.0))
            .flex()
            .items_center()
            .justify_center()
            .rounded(px(3.0))
            .bg(badge_color)
            .text_xs()
            .font_weight(gpui::FontWeight::BOLD)
            .text_color(gpui::white())
            .child(badge_text),
    )
})

S / L / E / Z / H / X 六个类型徽章走的是同一个分支,理论上都会中招,只是这次被 zset 撞上了。

两点建议:

  1. text.rs:650 那个 unwrap() 建议降级为「跳过这次绘制」而不是 panic —— 一个文本没被 measure 到,不应该让整个应用消失。
  2. 根因看起来是这种固定尺寸(18×18) + flex 居中的文本元素,在某些布局时序下走完了 prepaint 却没走 measure。六个徽章是同一套写法,可以一起看。

另外顺带一提:panic = "abort" 让任何这类小 bug 都升级成「整个应用消失 + 未保存的工作丢失」。是否值得考虑把这一项改回 unwind,或至少加一个落盘的 panic hook?我在 ~/.config/navop/logs/navop.log 里完全找不到这次崩溃的痕迹(日志里有启动、有 license、有 key type fetched,唯独没有 panic 那行),这是这次定位花了不少时间的主要原因。

Activity

  1. added a commit that references this issue on Oct 16, 2026
  2. added a commit that references this issue on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions