niri-wm/niri · error · anyhow::Error
Condition failed: `outputs.len() == 1`
Error message
Condition failed: `outputs.len() == 1`
What it means
Niri::screenshot_all_outputs implements the compositor-wide screenshot (the 'screenshot' action / screenshot API). It collects all outputs from the global space and asserts exactly one, with a FIXME noting multi-output support (multi-scale handling and cropping) is not implemented. With two or more active outputs the ensure! fails and the screenshot aborts with this condition message.
Source
Thrown at src/niri.rs:5798
Ok(())
}
#[cfg(feature = "dbus")]
pub fn screenshot_all_outputs(
&mut self,
renderer: &mut GlesRenderer,
include_pointer: bool,
on_done: impl FnOnce(PathBuf) + Send + 'static,
) -> anyhow::Result<()> {
let _span = tracy_client::span!("Niri::screenshot_all_outputs");
self.update_render_elements(None);
let outputs: Vec<_> = self.global_space.outputs().cloned().collect();
// FIXME: support multiple outputs, needs fixing multi-scale handling and cropping.
anyhow::ensure!(outputs.len() == 1);
let output = outputs.into_iter().next().unwrap();
let geom = self.global_space.output_geometry(&output).unwrap();
let output_scale = output.current_scale().integer_scale();
let geom = geom.to_physical(output_scale);
let size = geom.size;
let transform = output.current_transform();
let size = transform.transform_size(size);
let ctx = RenderCtx {
renderer,
target: RenderTarget::ScreenCapture,
xray: None,
};
let elements = self.render_to_vec(ctx, &output, include_pointer);
let elements = elements.iter().rev();View on GitHub (pinned to 606284464d)
Solutions
- Use the per-output screenshot instead: 'niri msg action screenshot-screen' (screenshots the focused output) — this path has no single-output restriction.
- If the all-outputs screenshot is required, temporarily reduce to one active output (disable the others via 'niri msg output <name> off') and re-enable afterwards.
- Track/update niri: the FIXME (multi-scale handling and cropping) marks this as a known gap that later versions may close.
Example fix
// before: multiple monitors -> Condition failed: `outputs.len() == 1` niri msg action screenshot // after: screenshot the focused output, works with any output count niri msg action screenshot-screen
Defensive patterns
Strategy: validation
Validate before calling
// Rust: gate the all-outputs screenshot on the supported precondition
let count = niri.global_space().outputs().count();
if count != 1 {
// route to the per-output path that supports any number of outputs
return screenshot_focused_output(niri, renderer, on_done);
} Type guard
fn supports_all_outputs_screenshot(niri: &Niri) -> bool {
niri.global_space().outputs().count() == 1
} Try / catch
match niri.screenshot_all_outputs(renderer, include_pointer, on_done) {
Ok(path) => Ok(path),
Err(e) if e.to_string().contains("outputs.len() == 1") => {
// known limitation: retry per-output instead of failing the user action
niri.screenshot_screen(renderer, /* focused */, include_pointer, on_done)
}
Err(e) => Err(e),
} Prevention
- Bind screenshot-screen (per-output) in configs intended for multi-monitor setups.
- Before scripting 'niri msg action screenshot', check 'niri msg outputs' count is 1.
- Watch release notes — the FIXME marks multi-output screenshots as a planned fix.
When it happens
Trigger: Invoking a full screenshot while more than one output is connected and enabled: two monitors, or a laptop panel plus an external display. Per-output 'screenshot-screen' takes a different code path and is unaffected.
Common situations: Users with multi-monitor setups pressing the screenshot bind that calls screenshot (all outputs) instead of screenshot-screen; automation/scripts using the screenshot IPC action on multi-head systems; mirroring setups that still count as two outputs.
AI-assisted analysis of niri-wm/niri@606284464d (2026-08-16).
Data as JSON: /api/errors/1e4fb3b64bae1745.
Report an issue: GitHub.