{"record":{"id":"1e4fb3b64bae1745","repo":"niri-wm/niri","slug":"condition-failed-outputs-len-1","errorCode":null,"errorMessage":"Condition failed: `outputs.len() == 1`","messagePattern":"Condition failed: `outputs\\.len\\(\\) == 1`","errorType":"console","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/niri.rs","lineNumber":5798,"sourceCode":"\n        Ok(())\n    }\n\n    #[cfg(feature = \"dbus\")]\n    pub fn screenshot_all_outputs(\n        &mut self,\n        renderer: &mut GlesRenderer,\n        include_pointer: bool,\n        on_done: impl FnOnce(PathBuf) + Send + 'static,\n    ) -> anyhow::Result<()> {\n        let _span = tracy_client::span!(\"Niri::screenshot_all_outputs\");\n\n        self.update_render_elements(None);\n\n        let outputs: Vec<_> = self.global_space.outputs().cloned().collect();\n\n        // FIXME: support multiple outputs, needs fixing multi-scale handling and cropping.\n        anyhow::ensure!(outputs.len() == 1);\n\n        let output = outputs.into_iter().next().unwrap();\n        let geom = self.global_space.output_geometry(&output).unwrap();\n\n        let output_scale = output.current_scale().integer_scale();\n        let geom = geom.to_physical(output_scale);\n\n        let size = geom.size;\n        let transform = output.current_transform();\n        let size = transform.transform_size(size);\n\n        let ctx = RenderCtx {\n            renderer,\n            target: RenderTarget::ScreenCapture,\n            xray: None,\n        };\n        let elements = self.render_to_vec(ctx, &output, include_pointer);\n        let elements = elements.iter().rev();","sourceCodeStart":5780,"sourceCodeEnd":5816,"githubUrl":"https://github.com/niri-wm/niri/blob/606284464d4a99bb35710fee68192bc71085ee7c/src/niri.rs#L5780-L5816","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: multiple monitors -> Condition failed: `outputs.len() == 1`\nniri msg action screenshot\n\n// after: screenshot the focused output, works with any output count\nniri msg action screenshot-screen","handlingStrategy":"validation","validationCode":"// Rust: gate the all-outputs screenshot on the supported precondition\nlet count = niri.global_space().outputs().count();\nif count != 1 {\n    // route to the per-output path that supports any number of outputs\n    return screenshot_focused_output(niri, renderer, on_done);\n}","typeGuard":"fn supports_all_outputs_screenshot(niri: &Niri) -> bool {\n    niri.global_space().outputs().count() == 1\n}","tryCatchPattern":"match niri.screenshot_all_outputs(renderer, include_pointer, on_done) {\n    Ok(path) => Ok(path),\n    Err(e) if e.to_string().contains(\"outputs.len() == 1\") => {\n        // known limitation: retry per-output instead of failing the user action\n        niri.screenshot_screen(renderer, /* focused */, include_pointer, on_done)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["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."],"tags":["screenshot","multi-monitor","outputs","assertion","known-limitation"],"backgroundTag":"assertion-failed","analyzedSha":"606284464d4a99bb35710fee68192bc71085ee7c","analyzedAt":"2026-08-16T21:48:00.228Z","schemaVersion":2},"datasetVersion":"2026-08-18T00:17:09.346Z"}