iced-rs/iced · error
Editor should always be initialized
Error message
Editor should always be initialized
What it means
`graphics::text::Editor` keeps its state as `Option<Arc<Internal>>`. Mutating methods run through `with_internal_mut`, which `take()`s the Option, mutates, and puts it back — so the Option is None for the duration. `internal().expect("Editor should always be initialized")` fires when a read method (buffer, cursor, line_count, ...) runs in that window: either a previous mutation panicked midway leaving it permanently None, or code re-entered the Editor from inside a mutation.
Source
Thrown at graphics/src/text/editor.rs:59
/// Creates a [`Weak`] reference to the [`Editor`].
///
/// This is useful to avoid cloning the [`Editor`] when
/// referential guarantees are unnecessary. For instance,
/// when creating a rendering tree.
pub fn downgrade(&self) -> Weak {
let editor = self.internal();
Weak {
raw: Arc::downgrade(editor),
bounds: editor.bounds,
}
}
fn internal(&self) -> &Arc<Internal> {
self.0
.as_ref()
.expect("Editor should always be initialized")
}
fn with_internal_mut<T>(&mut self, f: impl FnOnce(&mut Internal) -> T) -> T {
let editor = self.0.take().expect("Editor should always be initialized");
// TODO: Handle multiple strong references somehow
let mut internal =
Arc::try_unwrap(editor).expect("Editor cannot have multiple strong references");
// Clear cursor cache
let _ = internal
.selection
.write()
.expect("Write to cursor cache")
.take();
let result = f(&mut internal);
View on GitHub (pinned to 2cffa99b39)
Solutions
- Find the FIRST panic in a mutating method — this message means self.0 was left None by it
- Never call Editor read methods from inside closures passed to mutating methods
- If you recover via catch_unwind, replace the editor (Editor::new + re-feed content) instead of reusing it
- Minimize the mutation window: prefer one perform() call over repeated small mutations
Defensive patterns
Strategy: validation
Try / catch
let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
editor.perform(action);
}));
if outcome.is_err() {
// self.0 was left None — rebuild instead of reusing the damaged editor
editor = Editor::new();
editor.load(&contents);
} Prevention
- Never call read methods (buffer/cursor/line_count) on the Editor from inside a mutating closure on that same editor
- After any caught panic in an edit path, rebuild the Editor — the internal Option stays None otherwise
- Deliver edit events through a queue applied sequentially instead of re-entrant perform() calls
- Reproduce the first panic with a minimal typing/paste/selection script and report it if it is inside iced
When it happens
Trigger: Any read on the Editor after an earlier mutating method (perform/apply/backspace/...) panicked inside with_internal_mut and never restored self.0; or calling read methods re-entrantly from the closure passed to a mutating method on the same editor.
Common situations: A cosmic-text panic during an edit that a crash handler caught, leaving a zombie editor; widget code that triggers a redraw/read of the editor from inside an update/perform callback on that same editor.
Related errors
- Editor cannot have multiple strong references
- Hot function is stale
- Write to font system
- Read from font system
- Write font system
AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16).
Data as JSON: /api/errors/7d43520c1927a758.
Report an issue: GitHub.