{"record":{"id":"62d2c45881be5ec9","repo":"iced-rs/iced","slug":"render-cached-text","errorCode":null,"errorMessage":"Render cached text","messagePattern":"Render cached text","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"wgpu/src/text.rs","lineNumber":415,"sourceCode":"        render_pass.set_scissor_rect(bounds.x, bounds.y, bounds.width, bounds.height);\n\n        for item in batch {\n            match item {\n                Item::Group { .. } => {\n                    let renderer = &self.renderers[start + layer_count];\n\n                    renderer\n                        .render(&atlas, &viewport.0, render_pass)\n                        .expect(\"Render text\");\n\n                    layer_count += 1;\n                }\n                Item::Cached { cache, .. } => {\n                    if let Some((atlas, upload)) = self.storage.get(cache) {\n                        upload\n                            .renderer\n                            .render(atlas, &viewport.0, render_pass)\n                            .expect(\"Render cached text\");\n                    }\n                }\n            }\n        }\n\n        layer_count\n    }\n\n    pub fn trim(&mut self) {\n        self.cache.trim();\n        self.storage.trim();\n\n        self.prepare_layer = 0;\n    }\n}\n\nfn prepare(\n    device: &wgpu::Device,","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/iced-rs/iced/blob/2cffa99b395d84fe469b44dccb56bbacd2f1a157/wgpu/src/text.rs#L397-L433","documentation":"This panic fires inside iced's wgpu backend when cryoglyph's TextRenderer::render returns an error while drawing a cached text layer — text laid out in an earlier frame and kept in Storage, then re-rendered via `upload.renderer.render(atlas, &viewport.0, render_pass)` at wgpu/src/text.rs:410-416. The failure is almost always RenderError::RemovedFromAtlas: a glyph this renderer placed in the glyph atlas was evicted, or the atlas was reallocated, between the prepare and render phases; a lost GPU device produces the same panic via the atlas render error. Because iced unwraps with .expect(\"Render cached text\"), the render thread panics and the process aborts. It is an internal iced_wgpu/cryoglyph failure (iced calls the fork of glyphon, see Cargo.toml: `cryoglyph`), not a mistake in application code.","triggerScenarios":"(1) Resizing the window while cached text layers exist, so the atlas/viewport state baked in at prepare no longer matches what render sees. (2) A frame prepares enough new text (Item::Group) that the shared glyph atlas grows or evicts glyphs still owned by a previously cached layer. (3) The cached layer renders after a GPU device-lost/driver reset invalidated its atlas. (4) Sustained high atlas pressure: many font families, weights, or very large font sizes. Panic path: iced_wgpu::text::State::render -> Item::Cached -> storage.get(cache) -> renderer.render(...).expect(\"Render cached text\").","commonSituations":"Text-heavy iced apps (log viewers, terminals, editors, chat clients) during rapid resize or scrolling; apps loading many fonts or huge CJK/icon fonts; machines with flaky GPU drivers where wgpu logs 'device lost' before the crash; regressions between iced point releases (0.13/0.14/0.15-dev) as the text-layer cache and the cryoglyph fork evolved.","solutions":["Update iced to the latest release and pin it — this panic lives in iced_wgpu/cryoglyph internals and atlas-eviction/resize occurrences have been fixed across releases; reproduce on the newest version before anything else.","Reduce glyph atlas pressure: load fewer font families and weights, avoid extremely large font sizes and huge offscreen/invisible text blocks, and render very long content in virtualized/lazy lists so not every glyph is prepared each frame.","If it happens only on some machines, check GPU stability: look for 'device lost' in wgpu logs, update GPU drivers, and test with software rendering (LIBGL_ALWAYS_SOFTWARE=1, WGPU_BACKEND=gl) to distinguish a driver reset from an iced bug.","Reproduce with RUST_BACKTRACE=1 and RUST_LOG=iced_wgpu=debug to capture the failing path and the frame that triggers it, then report it at https://github.com/iced-rs/iced/issues with a minimal reproducer (include the resize/scroll steps).","As a stopgap for shipped apps, switch the backend from wgpu to iced's tiny-skia software renderer, which does not use this glyph-atlas path."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// iced unwraps internally, so the only guard is a top-level panic boundary\n// that degrades instead of dying (kiosk / shipped apps):\nfn main() -> iced::Result {\n    let run = || iced::application(\"App\", Update::new, View::new).run();\n    match std::panic::catch_unwind(run) {\n        Ok(result) => result,\n        Err(panic) => {\n            log::error!(\"wgpu backend panicked: {panic:?}\");\n            // fall back to the tiny-skia software backend (no glyph atlas path)\n            iced::application(\"App\", Update::new, View::new).run()\n        }\n    }\n}","preventionTips":["Pin the exact iced version you tested (e.g. `iced = \"=0.14.2\"`) so minor releases cannot introduce text-renderer regressions unnoticed.","Exercise rapid window resize and scrolling on every supported platform in QA — most cached-text panics only appear under resize/atlas pressure.","Keep font sets small: strip unused weights and subset large CJK/icon fonts; every distinct font-family/size/style combination adds atlas entries.","Watch RUST_LOG=iced_wgpu=debug,wgpu=warn output during QA for 'atlas full' or 'device lost' messages that precede this panic."],"tags":["rust","iced","wgpu","cryoglyph","text-rendering","glyph-atlas","panic","window-resize"],"backgroundTag":"glyph-atlas-eviction","analyzedSha":"2cffa99b395d84fe469b44dccb56bbacd2f1a157","analyzedAt":"2026-08-16T19:41:49.083Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}