denisidoro/navi · error

Unable to get variable

Error message

Unable to get variable

What it means

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".

Source

Thrown at src/commands/preview/var_stdin.rs:19

use clap::Args;

use super::var;
use crate::common::shell::{self, ShellSpawnError, EOF};
use crate::prelude::*;
use std::io::{self, Read};

#[derive(Debug, Clone, Args)]
pub struct Input {}

impl Runnable for Input {
    fn run(&self) -> Result<()> {
        let mut text = String::new();
        io::stdin().read_to_string(&mut text)?;

        let mut parts = text.split(EOF);
        let selection = parts.next().expect("Unable to get selection").to_owned();
        let query = parts.next().expect("Unable to get query").to_owned();
        let variable = parts.next().expect("Unable to get variable").trim().to_owned();

        let input = var::Input {
            selection,
            query,
            variable,
        };

        input.run()?;

        if let Some(extra) = parts.next() {
            if !extra.is_empty() {
                print!("");

                let mut cmd = shell::out();
                cmd.arg(extra);
                debug!(?cmd);
                cmd.spawn().map_err(|e| ShellSpawnError::new(extra, e))?.wait()?;
            }

View on GitHub (pinned to f7330b9ad5)

Solutions

  1. Add the VARIABLE placeholder as the third EOF-separated field in the finder preview command template
  2. Diff your finder preview config against the one shipped by this CLI version and update it
  3. Manually pipe all three fields to verify the protocol before re-running the finder
  4. Swap the `expect` for `ok_or_else(|| anyhow!(...))?` in library code

Example fix

// before
let variable = parts.next().expect("Unable to get variable").trim().to_owned();
// after
let variable = parts.next().ok_or_else(|| anyhow!("Unable to get variable from stdin payload"))?.trim().to_owned();
Defensive patterns

Strategy: validation

Validate before calling

let fields: Vec<&str> = text.split(EOF).collect();
if fields.len() < 3 {
    eprintln!("stdin payload missing variable field (need 3 EOF-separated fields)");
}

Type guard

fn has_variable(text: &str) -> bool {
    text.split(EOF).nth(2).map_or(false, |v| !v.trim().is_empty())
}

Try / catch

let variable = text.split(EOF).nth(2)
    .map(str::trim)
    .filter(|v| !v.is_empty())
    .ok_or_else(|| anyhow!("no variable in stdin payload"))?;
// guard the payload shape before constructing var::Input

Prevention

When it happens

Trigger: The stdin payload ended after the query field — the finder preview template omitted the VARIABLE placeholder or trailing EOF-separated field.

Common situations: 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.

Related errors


AI-assisted analysis of denisidoro/navi@f7330b9ad5 (2026-09-03). Data as JSON: /api/errors/b74e1be2233f816c. Report an issue: GitHub.