GraphiteEditor/Graphite · error
Failed to download texture data
Error message
Failed to download texture data
What it means
The single-texture download path (texture_conversion.rs:233) submits a copy encoder, then the converter maps its readback buffer by polling the device and awaiting the map_async result over a channel; converter.convert(device).await returns Err when that map is rejected, and .expect("Failed to download texture data") panics. It is the single-raster variant of the batch failure at line 219, with the same wgpu root causes.
Source
Thrown at node-graph/libraries/wgpu-executor/src/texture_conversion.rs:246
.collect()
}
}
/// Converts single GPU raster to CPU by downloading texture data
impl<'i> Convert<Raster<CPU>, &'i WgpuExecutor> for Raster<GPU> {
async fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> Raster<CPU> {
let device = &executor.context().device;
let queue = &executor.context().queue;
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("single_texture_download_encoder"),
});
let converter = RasterGpuToRasterCpuConverter::new(device, &mut encoder, self);
queue.submit([encoder.finish()]);
converter.convert(device).await.expect("Failed to download texture data")
}
}
View on GitHub (pinned to c507b35645)
Solutions
- Determine whether the device was lost: enable wgpu logging / uncaptured-error handler; on device loss, re-create the executor and retry the download once
- Keep the converter and its buffer alive until convert() resolves; do not free GPU resources during pending maps
- Replace .expect with error propagation so callers can retry or report a user-visible failure
- If reproducible for specific textures, check them for extreme dimensions or formats that make the copy/readback invalid
Example fix
// before
converter.convert(device).await.expect("Failed to download texture data")
// after
converter.convert(device).await.map_err(|_| TextureDownloadError::MapFailed)? // caller re-creates the executor on device loss, then retries Defensive patterns
Strategy: retry
Validate before calling
// Before downloading, confirm the texture is non-degenerate and the device is responsive: assert!(texture.width() > 0 && texture.height() > 0); let _ = device.poll(wgpu::wgt::PollType::wait_indefinitely()); // surfaces queued errors early
Try / catch
use futures::FutureExt;
let attempt = std::panic::AssertUnwindSafe(raster_gpu.convert(footprint, executor)).catch_unwind().await;
match attempt {
Ok(cpu) => { /* success */ }
Err(_) => { /* re-create the executor (device loss is the usual cause) and retry the download once */ }
} Prevention
- Do not issue texture downloads while the executor/device is being torn down (document close, app exit)
- Log wgpu uncaptured errors and device-lost callbacks so the root cause is visible before this panic
- On flaky VM/software adapters, wrap single downloads with one retry
When it happens
Trigger: Downloading one GPU texture to a CPU raster when the device is lost (driver reset), when the readback buffer is invalid or dropped before the map completes, when map_async is rejected due to the buffer's state, or when the channel delivering the map result breaks during executor teardown.
Common situations: Exporting or screenshotting a single rendered image immediately after heavy GPU work; running under remote desktop/VM software adapters; wgpu upgrades; downloads issued while the editor/executor is being torn down (document closed mid-evaluation).
Related errors
- Buffer mapping communication failed
- Failed to create WGPU context
- GPU executor should be available when we receive a texture
- ApplicationIo not available
- GPU executor not available
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/be952c9508236cc3.
Report an issue: GitHub.