{"record":{"id":"b74e1be2233f816c","repo":"denisidoro/navi","slug":"unable-to-get-variable","errorCode":null,"errorMessage":"Unable to get variable","messagePattern":"Unable to get variable","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/commands/preview/var_stdin.rs","lineNumber":19,"sourceCode":"use clap::Args;\n\nuse super::var;\nuse crate::common::shell::{self, ShellSpawnError, EOF};\nuse crate::prelude::*;\nuse std::io::{self, Read};\n\n#[derive(Debug, Clone, Args)]\npub struct Input {}\n\nimpl Runnable for Input {\n    fn run(&self) -> Result<()> {\n        let mut text = String::new();\n        io::stdin().read_to_string(&mut text)?;\n\n        let mut parts = text.split(EOF);\n        let selection = parts.next().expect(\"Unable to get selection\").to_owned();\n        let query = parts.next().expect(\"Unable to get query\").to_owned();\n        let variable = parts.next().expect(\"Unable to get variable\").trim().to_owned();\n\n        let input = var::Input {\n            selection,\n            query,\n            variable,\n        };\n\n        input.run()?;\n\n        if let Some(extra) = parts.next() {\n            if !extra.is_empty() {\n                print!(\"\");\n\n                let mut cmd = shell::out();\n                cmd.arg(extra);\n                debug!(?cmd);\n                cmd.spawn().map_err(|e| ShellSpawnError::new(extra, e))?.wait()?;\n            }","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/denisidoro/navi/blob/f7330b9ad5bd95b7d1a3c96d00e0a77deb589147/src/commands/preview/var_stdin.rs#L1-L37","documentation":"Third field of the `var_stdin` stdin protocol: the variable name. If the payload has selection and query but no trailing variable field, `parts.next()` returns `None` and the `expect` panics with \"Unable to get variable\".","triggerScenarios":"The stdin payload ended after the query field — the finder preview template omitted the VARIABLE placeholder or trailing EOF-separated field.","commonSituations":"Partial migration of the finder preview command when the protocol grew to three fields; a preview invocation copy-pasted from an older config; template whitespace/quoting dropping the last field.","solutions":["Add the VARIABLE placeholder as the third EOF-separated field in the finder preview command template","Diff your finder preview config against the one shipped by this CLI version and update it","Manually pipe all three fields to verify the protocol before re-running the finder","Swap the `expect` for `ok_or_else(|| anyhow!(...))?` in library code"],"exampleFix":"// before\nlet variable = parts.next().expect(\"Unable to get variable\").trim().to_owned();\n// after\nlet variable = parts.next().ok_or_else(|| anyhow!(\"Unable to get variable from stdin payload\"))?.trim().to_owned();","handlingStrategy":"validation","validationCode":"let fields: Vec<&str> = text.split(EOF).collect();\nif fields.len() < 3 {\n    eprintln!(\"stdin payload missing variable field (need 3 EOF-separated fields)\");\n}","typeGuard":"fn has_variable(text: &str) -> bool {\n    text.split(EOF).nth(2).map_or(false, |v| !v.trim().is_empty())\n}","tryCatchPattern":"let variable = text.split(EOF).nth(2)\n    .map(str::trim)\n    .filter(|v| !v.is_empty())\n    .ok_or_else(|| anyhow!(\"no variable in stdin payload\"))?;\n// guard the payload shape before constructing var::Input","preventionTips":["Include the VARIABLE placeholder as the trailing field in finder preview templates","Diff your preview config against the version shipped by the CLI after upgrades","Write a small test that pipes all three fields into the preview command","Treat '2 fields received' as a config-drift signal"],"tags":["rust","panic","stdin","preview"],"backgroundTag":"malformed-stdin-payload","analyzedSha":"f7330b9ad5bd95b7d1a3c96d00e0a77deb589147","analyzedAt":"2026-09-03T13:58:22.429Z","contentChangedAt":"2026-09-03T13:58:22.429Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}