{"record":{"id":"7d43520c1927a758","repo":"iced-rs/iced","slug":"editor-should-always-be-initialized","errorCode":null,"errorMessage":"Editor should always be initialized","messagePattern":"Editor should always be initialized","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graphics/src/text/editor.rs","lineNumber":59,"sourceCode":"\n    /// Creates a [`Weak`] reference to the [`Editor`].\n    ///\n    /// This is useful to avoid cloning the [`Editor`] when\n    /// referential guarantees are unnecessary. For instance,\n    /// when creating a rendering tree.\n    pub fn downgrade(&self) -> Weak {\n        let editor = self.internal();\n\n        Weak {\n            raw: Arc::downgrade(editor),\n            bounds: editor.bounds,\n        }\n    }\n\n    fn internal(&self) -> &Arc<Internal> {\n        self.0\n            .as_ref()\n            .expect(\"Editor should always be initialized\")\n    }\n\n    fn with_internal_mut<T>(&mut self, f: impl FnOnce(&mut Internal) -> T) -> T {\n        let editor = self.0.take().expect(\"Editor should always be initialized\");\n\n        // TODO: Handle multiple strong references somehow\n        let mut internal =\n            Arc::try_unwrap(editor).expect(\"Editor cannot have multiple strong references\");\n\n        // Clear cursor cache\n        let _ = internal\n            .selection\n            .write()\n            .expect(\"Write to cursor cache\")\n            .take();\n\n        let result = f(&mut internal);\n","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/iced-rs/iced/blob/2cffa99b395d84fe469b44dccb56bbacd2f1a157/graphics/src/text/editor.rs#L41-L77","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    editor.perform(action);\n}));\nif outcome.is_err() {\n    // self.0 was left None — rebuild instead of reusing the damaged editor\n    editor = Editor::new();\n    editor.load(&contents);\n}","preventionTips":["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"],"tags":["rust","iced","graphics","text-editor","reentrancy","panic","invariant"],"backgroundTag":"use-after-take-panic","analyzedSha":"2cffa99b395d84fe469b44dccb56bbacd2f1a157","analyzedAt":"2026-08-16T19:41:49.083Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}