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

  1. Determine whether the device was lost: enable wgpu logging / uncaptured-error handler; on device loss, re-create the executor and retry the download once
  2. Keep the converter and its buffer alive until convert() resolves; do not free GPU resources during pending maps
  3. Replace .expect with error propagation so callers can retry or report a user-visible failure
  4. 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

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


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/be952c9508236cc3. Report an issue: GitHub.