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

  1. Find the FIRST panic in a mutating method — this message means self.0 was left None by it
  2. Never call Editor read methods from inside closures passed to mutating methods
  3. If you recover via catch_unwind, replace the editor (Editor::new + re-feed content) instead of reusing it
  4. 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

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


AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16). Data as JSON: /api/errors/7d43520c1927a758. Report an issue: GitHub.