emilk/egui · error

Failed to save screenshot to {path:?}: {err}

Error message

Failed to save screenshot to {path:?}: {err}

What it means

In eframe's glow integration, when the app exits with `screenshot_on_save`/`--screenshot` behavior, `save_screenshot_and_exit` writes the captured framebuffer to disk with the `image` crate. If `image::save_buffer` fails (bad path, unwritable directory, I/O error), the code panics with this message before calling `std::process::exit(0)`.

Source

Thrown at crates/eframe/src/native/glow_integration.rs:1773

fn save_screenshot_and_exit(
    path: &str,
    painter: &egui_glow::Painter,
    screen_size_in_pixels: [u32; 2],
) {
    assert!(
        egui::load::has_extension(path, "png"),
        "Expected EFRAME_SCREENSHOT_TO to end with '.png', got {path:?}"
    );
    let screenshot = painter.read_screen_rgba(screen_size_in_pixels);
    image::save_buffer(
        path,
        screenshot.as_raw(),
        screenshot.width() as u32,
        screenshot.height() as u32,
        image::ColorType::Rgba8,
    )
    .unwrap_or_else(|err| {
        panic!("Failed to save screenshot to {path:?}: {err}");
    });
    log::info!("Screenshot saved to {path:?}.");

    #[expect(clippy::exit)]
    std::process::exit(0);
}

View on GitHub (pinned to 441971a776)

Solutions

  1. Ensure the parent directory of the screenshot path exists (create it with `std::fs::create_dir_all` before running).
  2. Verify the path is writable by the user running the app (fix permissions or choose another output location).
  3. Check the embedded `err` in the panic message for the underlying I/O cause (e.g. NotFound, PermissionDenied) and address it.
  4. If path is constructed at runtime, log/validate it before the run; use an absolute path to avoid CWD surprises in CI.

Example fix

// before
std::fs::create_dir("screenshots")?; // fails if exists, or wrong dir
// after
std::fs::create_dir_all("screenshots/shots")?; // ensure full path exists before screenshot mode writes there
Defensive patterns

Strategy: validation

Validate before calling

let path = std::path::Path::new("shots/app.png");
if let Some(dir) = path.parent() {
    std::fs::create_dir_all(dir).expect("create screenshot dir");
}
assert!(!dir_is_readonly(dir), "screenshot dir must be writable");

Try / catch

// if writing screenshots yourself:
if let Err(err) = image::save_buffer(path, data, w, h, image::ColorType::Rgba8) {
    log::error!("screenshot save failed: {err}");
    // fallback path or exit non-zero without panic
}

Prevention

When it happens

Trigger: Running an eframe app in screenshot mode (e.g. `NativeOptions { screenshot_on_save: true }` or CLI screenshot flag) where the target `path` is invalid, the parent directory doesn't exist, the process lacks write permission, or the disk is full so `image::save_buffer` returns Err.

Common situations: CI pipelines running headless screenshot tests with a relative output path that resolves to a non-existent directory; read-only containers passing an unwritable path; typos in the screenshot file path or unsupported extension.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of emilk/egui@441971a776 (2026-09-12). Data as JSON: /api/errors/d5964a92597c03d6. Report an issue: GitHub.