{"record":{"id":"59f92bc162f38501","repo":"niri-wm/niri","slug":"niri-returned-an-error","errorCode":null,"errorMessage":"niri returned an error","messagePattern":"niri returned an error","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/ipc/client.rs","lineNumber":111,"sourceCode":"                eprintln!(\"Compositor version: {compositor_version}\");\n                eprintln!(\"CLI version:        {cli_version}\");\n                eprintln!(\"Did you forget to restart niri after an update?\");\n                eprintln!();\n            }\n        }\n        Some(_) => {\n            eprintln!(\"Unable to get the running niri compositor version.\");\n            eprintln!(\"Did you forget to restart niri after an update?\");\n            eprintln!();\n        }\n        None => {\n            // Communication error, or the original request was already a version request, or the\n            // original request had succeeded. Don't add irrelevant context.\n        }\n    }\n\n    let reply = result.context(\"error communicating with niri\")?;\n    let response = reply.map_err(|err_msg| anyhow!(err_msg).context(\"niri returned an error\"))?;\n\n    match msg {\n        Msg::RequestError => {\n            bail!(\"unexpected response: expected an error, got {response:?}\");\n        }\n        Msg::Version => {\n            let Response::Version(compositor_version) = response else {\n                bail!(\"unexpected response: expected Version, got {response:?}\");\n            };\n\n            let cli_version = version();\n\n            if json {\n                println!(\n                    \"{}\",\n                    json!({\n                        \"compositor\": compositor_version,\n                        \"cli\": cli_version,","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/niri-wm/niri/blob/606284464d4a99bb35710fee68192bc71085ee7c/src/ipc/client.rs#L93-L129","documentation":"niri's IPC client (niri msg / niri-ipc) sends a request over the Unix socket and the compositor replies either with a payload or an error string. This message is the client-side wrapper: the reply was an error response, and err_msg contains the compositor's reason (e.g. 'no such output', 'invalid value'). It means the connection worked and the protocol was understood — the request itself was rejected.","triggerScenarios":"Any niri msg action the compositor refuses: focusing or moving a workspace to a nonexistent output, referencing a window/workspace by an id that no longer exists, an unknown action name (version skew between CLI and running compositor), or invalid arguments to actions like set-window-width.","commonSituations":"Scripts hardcoding output names (eDP-1 vs DP-1) after re-docking; racing a window close (window id gone by the time the command runs); running a newer/older niri msg binary against a compositor started before/after an update (IPC schema mismatch); typos in action names in config binds or shell scripts.","solutions":["Read err_msg in the error chain — it names the exact reason ('unknown output', 'no window with id', etc.) and points at the offending argument.","Discover valid targets before acting: 'niri msg outputs', 'niri msg workspaces', 'niri msg windows' and use those exact names/ids in the command.","After upgrading niri, restart the compositor so the running server and the niri msg client match; the 'Did you forget to restart niri after an update?' hint from the version check indicates exactly this.","In scripts, re-query ids immediately before using them and tolerate failure (the window may have closed between listing and acting)."],"exampleFix":"# before: output name guessed, compositor rejects it\nniri msg output focus HDMI-1\n# niri returned an error: unknown output: HDMI-1\n\n# after: list real outputs first, then use the exact name\nniri msg outputs\nniri msg output focus DP-1","handlingStrategy":"try-catch","validationCode":"# shell: validate targets before sending the request\nniri msg outputs | grep -q \"^Output \\\"DP-1\\\"\" || { echo \"no such output\" >&2; exit 1; }\nniri msg output DP-1 focus","typeGuard":null,"tryCatchPattern":"// Rust (niri-ipc client): distinguish rejection from transport failure and show the server's reason\nmatch ipc.send(msg).await {\n    Err(e) => return Err(e.context(\"error communicating with niri\")),\n    Ok(Reply::Err(reason)) => {\n        eprintln!(\"niri rejected the request: {reason}\");\n        // optionally re-query state (outputs/windows) and retry once with corrected args\n        std::process::exit(1);\n    }\n    Ok(Reply::Ok(resp)) => resp,\n}","preventionTips":["Discover-then-act: always list outputs/windows/workspaces first and feed exact names/ids into the action.","Restart niri and niri msg together after upgrades so the IPC schema matches.","Treat err_msg as authoritative input for scripts; do not parse the outer 'niri returned an error' wrapper.","Guard automation with existence checks (niri msg windows | grep id) to avoid races with closing windows."],"tags":["ipc","niri-msg","unix-socket","client","request-rejected"],"backgroundTag":"ipc-request-rejected","analyzedSha":"606284464d4a99bb35710fee68192bc71085ee7c","analyzedAt":"2026-08-16T21:48:00.228Z","schemaVersion":2},"datasetVersion":"2026-08-18T00:17:09.346Z"}