zed-industries/zed · warning
render_to_image unavailable while recovering from a lost…
Error message
render_to_image unavailable while recovering from a lost device
What it means
render_to_image is an offscreen-render API that must not run while the DirectX renderer is recovering from a lost GPU device. During recovery the `skip_draws` flag is set and the atlas still holds tile references belonging to the old device; drawing before the forced re-render would panic in DirectXAtlasTextures::texture. The renderer therefore rejects the call up front with this error via anyhow::ensure!.
Solutions
- Retry render_to_image after the device recovery completes (the forced re-render clears skip_draws); poll or await the renderer's recovery before retrying.
- Listen for the renderer's device-recovered signal/event and only call render_to_image after it fires.
- Fall back to a window-capture screenshot API when device recovery is in progress.
- If it persists, file a bug: skip_draws should clear after recovery, so it staying set indicates recovery never completed.
Example fix
// before
let image = renderer.render_to_image(&scene, appearance)?;
// after
let image = loop {
match renderer.render_to_image(&scene, appearance) {
Ok(image) => break image,
Err(e) if e.to_string().contains("recovering from a lost device") => {
smol::Timer::after(Duration::from_millis(100)).await;
}
Err(e) => return Err(e),
}
}; Defensive patterns
Strategy: retry
Validate before calling
// caller-side guard, if the renderer exposes skip_draws
if renderer.is_recovering_from_device_loss() {
return None; // defer the screenshot until recovery completes
} Try / catch
match renderer.render_to_image(&scene, appearance) {
Ok(img) => Some(img),
Err(e) if e.to_string().contains("lost device") => {
schedule_retry_after_device_recovery();
None
}
Err(e) => { log::error!("render_to_image failed: {e:#}"); None }
} Prevention
- Trigger screenshots/exports from device-recovered events, not immediately after resume/sleep
- Add bounded retry with backoff around render_to_image
- Watch for this error persisting — it indicates device recovery never completed and should be reported
When it happens
Trigger: Calling render_to_image (e.g. for screenshots/exports) between a device-lost event and completion of the forced re-render that rebuilds atlas tiles, i.e. any time `skip_draws` is still true.
Common situations: Taking a screenshot right after the machine resumes from sleep/hibernate, after driver reset (TDR), after GPU driver upgrade, or on remote-desktop/session reconnection — any event that invalidates the D3D device.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Device lost
- Device lost
- Failed to find fxc.exe
- no compatible surface formats
- Adapter (backend= , device= ) is not compatible with the…
AI-assisted analysis of zed-industries/zed@916fc2b8cb (2026-09-19).
Data as JSON: /api/errors/3e130e62ce0f013e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/gpui_windows/src/directx_renderer.rs:421
}
Ok(())
}
/// Render `scene` to an offscreen CPU image **without presenting** so
/// the window need never be shown or visible (the macOS headless path
/// goes through MetalRenderer; this is the Windows analogue). Draws into
/// the existing render target, copies it into a `D3D11_USAGE_STAGING`
/// texture, maps it, and converts BGRA to RGBA.
#[cfg(any(test, feature = "test-support"))]
pub(crate) fn render_to_image(
&mut self,
scene: &Scene,
background_appearance: WindowBackgroundAppearance,
) -> Result<image::RgbaImage> {
// A pending device-lost recovery (`skip_draws`) leaves the atlas holding
// tile references from the previous device; drawing before the forced
// re-render rebuilds them panics in `DirectXAtlasTextures::texture`.
anyhow::ensure!(
!self.skip_draws,
"render_to_image unavailable while recovering from a lost device"
);
self.render(scene, background_appearance)?;
let devices = self.devices.as_ref().context("devices missing")?;
let device = &devices.device;
let context = &devices.device_context;
let resources = self.resources.as_ref().context("resources missing")?;
let render_target = resources
.render_target
.as_ref()
.context("render target missing")?;
// A CPU-readable copy of the render target.
let mut desc = D3D11_TEXTURE2D_DESC::default();
unsafe { render_target.GetDesc(&mut desc) };
let width = desc.Width;View on GitHub (pinned to 916fc2b8cb)