Skip to main content

gpui-troubleshooting

Common errors and solutions for GPUI development. Use when debugging build errors, runtime panics, borrow checker issues, or unexpected behavior.

ソース情報

リポジトリ
zerx-lab/rmx
ソースの最終更新活動
2026年2月5日 09:49
検出された SKILL.md の言語
英語
スター
70
フォーク
2

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
gpui-troubleshooting
description
Common errors and solutions for GPUI development. Use when debugging build errors, runtime panics, borrow checker issues, or unexpected behavior.
# GPUI Troubleshooting This skill covers common errors and solutions when developing with GPUI. ## Borrow Checker Errors ### Multiple Borrow Error **Error**: Cannot borrow `cx` as mutable more than once **Solution**: Use the inner `cx` provided to closures, not the outer one ```rust // ❌ WRONG entity.update(cx, |view, inner_cx| { view.count += 1; cx.notify(); // Using outer cx - ERROR! }); // ✅ CORRECT entity.update(cx, |view, inner_cx| { view.count += 1; inner_cx.notify(); // Using inner cx }); ``` ### Moved Value Error **Error**: Use of moved value in async block **Solution**: Clone before moving into async block ```rust // ❌ WRONG cx.spawn(async move |this, cx| { self.data.do_something(); // ERROR: self moved }); // ✅ CORRECT let data = self.data.clone(); cx.spawn(async move |this, cx| { data.do_something(); }); ``` ## Entity Errors ### Update While Updating Panic **Error**: `already mutably borrowed: BorrowError` **Cause**: Trying to update an entity while it's already being updated **Solution**: Avoid nested entity updates ```rust // ❌ WRONG - will panic entity.update(cx, |view, cx| { entity.update(cx, |view2, cx2| { // Nested update - PANIC! }); }); // ✅ CORRECT - restructure logic entity.update(cx, |view, cx| { view.prepare_update(); }); // Update happens after first update completes entity.update(cx, |view, cx| { view.apply_update(); }); ``` ### WeakEntity Upgrade Failure **Error**: Panic when calling methods on `None` **Solution**: Always check `upgrade()` result ```rust // ❌ WRONG let entity = weak.upgrade().unwrap(); // May panic! // ✅ CORRECT if let Some(entity) = weak.upgrade() { entity.update(cx, |view, cx| { // ... }); } else { // Entity was dropped } // ✅ ALSO CORRECT (in async context) this.update(&mut *cx, |view, cx| { // ... })?; // Propagate error if entity gone ``` ## Async Errors ### "Nothing Left to Run" in Tests **Error**: `run_until_parked()` completes but test fails **Cause**: Using `smol::Timer` instead of GPUI timers **Solution**: Use GPUI executor timers ```rust // ❌ WRONG smol::Timer::after(Duration::from_secs(1)).await; // ✅ CORRECT cx.background_executor.timer(Duration::from_secs(1)).await; ``` ### Task Dropped Before Completion **Error**: Async work doesn't complete **Cause**: Task dropped without being awaited or detached **Solution**: Either detach or store the task ```rust // ❌ WRONG - task dropped immediately cx.spawn(async move |this, cx| { // Work... Ok(()) }); // ✅ CORRECT - detach cx.spawn(async move |this, cx| { // Work... Ok(()) }).detach(); // ✅ ALSO CORRECT - store self.current_task = Some(cx.spawn(async move |this, cx| { // Work... Ok(()) })); ``` ### Async Context Borrow Error **Error**: Cannot dereference `cx` in async context **Solution**: Use `&mut *cx` to dereference ```rust // ❌ WRONG cx.spawn(async move |this, cx| { this.update(cx, |view, cx| { // ERROR! // ... }); }); // ✅ CORRECT cx.spawn(async move |this, cx| { this.update(&mut *cx, |view, cx| { // ... })?; Ok(()) }); ``` ## Trait Errors ### IntoElement Not Implemented **Error**: `the trait IntoElement is not implemented for ...` **Solution**: Ensure type implements `IntoElement` or use `.child()` correctly ```rust // ❌ WRONG div().child(some_struct); // Error if SomeStruct doesn't impl IntoElement // ✅ CORRECT - use entity let entity = cx.new(|_| SomeStruct::new()); div().child(entity); // ✅ ALSO CORRECT - implement RenderOnce #[derive(IntoElement)] struct SomeStruct; impl RenderOnce for SomeStruct { fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement { div().child("Content") } } ``` ### Render Trait Signature Mismatch **Error**: Method signature doesn't match trait **Solution**: Ensure correct signature with `Window` and `Context<Self>` ```rust // ❌ WRONG impl Render for MyView { fn render(&mut self, cx: &mut Context<Self>) -> impl IntoElement { // Missing window parameter } } // ✅ CORRECT impl Render for MyView { fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement { div().child("Content") } } ``` ## UI Not Updating ### Forgetting cx.notify() **Symptom**: State changes but UI doesn't update **Solution**: Call `cx.notify()` after state changes ```rust // ❌ WRONG fn increment(&mut self, cx: &mut Context<Self>) { self.count += 1; // Missing cx.notify() - UI won't update! } // ✅ CORRECT fn increment(&mut self, cx: &mut Context<Self>) { self.count += 1; cx.notify(); // Trigger re-render } ``` ### Subscription Dropped **Symptom**: Events stop being received **Solution**: Store `Subscription` in a field ```rust // ❌ WRONG impl Parent { fn new(cx: &mut Context<Self>) -> Self { let child = cx.new(|_| Child::new()); cx.subscribe(&child, |this, _child, event, cx| { // Handle event }); // Subscription dropped here! Self { child } } } // ✅ CORRECT struct Parent { child: Entity<Child>, _subscription: Subscription, // Store to keep alive } impl Parent { fn new(cx: &mut Context<Self>) -> Self { let child = cx.new(|_| Child::new()); let subscription = cx.subscribe(&child, |this, _child, event, cx| { // Handle event }); Self { child, _subscription: subscription, } } } ``` ## Build Errors ### Missing Imports **Error**: Cannot find type/trait in this scope **Solution**: Import from `gpui::*` or specific module ```rust // Add at top of file use gpui::*; // Or specific imports use gpui::{ div, rgb, px, App, Context, Entity, Window, Render, IntoElement, RenderOnce, }; ``` ### Clippy Warnings Use project's clippy script: ```bash # ❌ WRONG cargo clippy # ✅ CORRECT (for Zed-based projects) ./script/clippy ``` ## Runtime Panics ### Index Out of Bounds **Error**: Panic from vector indexing **Solution**: Use safe access methods ```rust // ❌ WRONG let item = self.items[index]; // May panic! // ✅ CORRECT if let Some(item) = self.items.get(index) { // Use item } // ✅ ALSO CORRECT if index < self.items.len() { let item = &self.items[index]; } ``` ### Unwrap on None/Err **Error**: `called unwrap() on a None value` **Solution**: Never use `unwrap()` - use `?` or proper error handling ```rust // ❌ WRONG let value = option.unwrap(); // May panic! let result = fallible_op().unwrap(); // May panic! // ✅ CORRECT - propagate error let value = option.ok_or_else(|| anyhow::anyhow!("Missing value"))?; let result = fallible_op()?; // ✅ ALSO CORRECT - handle explicitly match option { Some(value) => { // Use value } None => { // Handle missing case } } ``` ## Common Mistakes Summary | Issue | Cause | Solution | |-------|-------|----------| | Multiple borrow | Using outer `cx` in closure | Use inner `cx` | | Update panic | Nested entity updates | Avoid nesting, restructure | | UI not updating | Missing `cx.notify()` | Call after state changes | | Task not running | Task dropped | Use `.detach()` or store task | | Test timeout | Using `smol::Timer` | Use GPUI `timer()` | | Events not received | Subscription dropped | Store in field | | Weak entity panic | Not checking `upgrade()` | Use `if let Some(...)` or `?` | | Unwrap panic | Calling `.unwrap()` | Use `?` or proper error handling | ## Debugging Tips 1. **Check the inner cx**: In update closures, always use the inner `cx` 2. **Verify notify calls**: Add `cx.notify()` after state changes 3. **Store subscriptions**: Keep `Subscription` values in struct fields 4. **Use GPUI timers in tests**: Replace `smol::Timer` with `cx.background_executor.timer()` 5. **Avoid unwrap**: Use `?` for error propagation or explicit error handling 6. **Check task lifecycle**: Ensure tasks are detached or stored, not dropped 7. **Watch for nested updates**: Avoid updating entities within update closures ## References - [GPUI Documentation](https://gpui.rs) - [Zed GEMINI.md](https://github.com/zed-industries/zed/blob/main/GEMINI.md)
GitHubで見る