a-b-street/abstreet · error · anyhow::Error

Can't take screenshots of dims

Error message

Can't take screenshots of dims {:?} when the window is only {:?}

What it means

screenshot_everything captures the window contents at the requested ScreenDims; if the requested dimensions exceed the actual canvas window size, offscreen rendering would clip the screenshot, so the library refuses up front with this bail. It is a guard against producing cropped/invalid screenshots. The message echoes the requested dims and the actual window dims.

Solutions

  1. Start the app with a window at least as large as the requested screenshot dims (increase the window/canvas size)
  2. Lower the requested dims to fit within the current window dims
  3. If supported, use a prerendered/offscreen render path at higher resolution instead of window capture
  4. Check state.canvas.get_window_dims() first and clamp the requested dims

Example fix

// before
screenshot_everything(dir, &prerender, zoom, ScreenDims::new(3840.0, 2160.0))?;
// after
let dims = ScreenDims::new(3840.0, 2160.0);
let (w, h) = state.canvas.get_window_dims();
let dims = ScreenDims::new(dims.width.min(w), dims.height.min(h));
screenshot_everything(dir, &prerender, zoom, dims)?;
Defensive patterns

Strategy: validation

Validate before calling

let (win_w, win_h) = state.canvas.get_window_dims();
assert!(dims.width <= win_w && dims.height <= win_h, "screenshot dims exceed window");

Type guard

fn dims_fit(dims: &ScreenDims, canvas: &Canvas) -> bool {
    dims.width <= canvas.window_width && dims.height <= canvas.window_height
}

Try / catch

match screenshot_everything(dir, &prerender, zoom, dims) {
    Ok(()) => (),
    Err(e) => eprintln!("screenshot skipped: {e}"),
}

Prevention

When it happens

Trigger: Calling screenshot_everything (via run) with a dims argument whose width or height is greater than state.canvas.window_width / window_height — typically when the CLI-specified screenshot size exceeds the window size the app was started with.

Common situations: Passing --dims larger than the default window without raising the window size; running in a smaller monitor/virtual display; automated screenshot harness reusing a fixed window size with bigger desired output.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/61aa1abf12194333. Report an issue: GitHub.

Appendix: source

Thrown at widgetry/src/tools/screenshot.rs:15

use abstutil::Timer;

use crate::runner::State;
use crate::{Prerender, ScreenDims, SharedAppState};

/// Take a screenshot of the entire canvas, tiling it based on the window's width and height.
pub(crate) fn screenshot_everything<A: 'static + SharedAppState>(
    state: &mut State<A>,
    dir_path: &str,
    prerender: &Prerender,
    zoom: f64,
    dims: ScreenDims,
) -> anyhow::Result<()> {
    if dims.width > state.canvas.window_width || dims.height > state.canvas.window_height {
        bail!(
            "Can't take screenshots of dims {:?} when the window is only {:?}",
            dims,
            state.canvas.get_window_dims()
        );
    }

    let mut timer = Timer::new("capturing screen");
    let num_tiles_x = (state.canvas.map_dims.0 * zoom / dims.width).ceil() as usize;
    let num_tiles_y = (state.canvas.map_dims.1 * zoom / dims.height).ceil() as usize;
    let orig_zoom = state.canvas.cam_zoom;
    let orig_x = state.canvas.cam_x;
    let orig_y = state.canvas.cam_y;

    timer.start_iter("capturing images", num_tiles_x * num_tiles_y);
    state.canvas.cam_zoom = zoom;
    fs_err::create_dir_all(dir_path)?;

    // See https://github.com/a-b-street/abstreet/issues/671 for context. Some maps are so large

View on GitHub (pinned to 0964f29315)