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.

Quellinformationen

Repository
zerx-lab/rmx
Letzte Quellaktivität
5. Februar 2026 um 09:49
Erkannte Sprache von SKILL.md
Englisch
Sterne
70
Forks
2

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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)
Auf GitHub ansehen