denisidoro/navi · error · anyhow

No variable captured in the line `{}`

Error message

No variable captured in the line `{}`

What it means

Thrown by `parse_variable_line` in src/parser.rs when `VAR_LINE_REGEX` matched the line but capture group 1 (the variable name) is absent. This is a defensive check: the overall regex matched, yet the variable capture is empty or optional and failed to extract.

Source

Thrown at src/parser.rs:93

        .context("Failed to parse finder options")?;

    let suggestion_type = match (multi, prevent_extra) {
        (true, _) => SuggestionType::MultipleSelections, // multi wins over prevent-extra
        (false, false) => SuggestionType::SingleRecommendation,
        (false, true) => SuggestionType::SingleSelection,
    };
    opts.suggestion_type = suggestion_type;

    Ok(opts)
}

fn parse_variable_line(line: &str) -> Result<(&str, &str, Option<FinderOpts>)> {
    let caps = VAR_LINE_REGEX
        .captures(line)
        .ok_or_else(|| anyhow!("No variables, command, and options found in the line `{}`", line))?;
    let variable = caps
        .get(1)
        .ok_or_else(|| anyhow!("No variable captured in the line `{}`", line))?
        .as_str()
        .trim();
    let mut command_plus_opts = caps
        .get(2)
        .ok_or_else(|| anyhow!("No command and options captured in the line `{}`", line))?
        .as_str()
        .split("---");
    let command = command_plus_opts
        .next()
        .ok_or_else(|| anyhow!("No command captured in the line `{}`", line))?;
    let command_options = command_plus_opts.next().map(parse_opts).transpose()?;
    Ok((variable, command, command_options))
}

fn without_prefix(line: &str) -> String {
    // The prefix character (#, %, @) is always 1-byte ASCII.
    // Skip it and let trim() handle any whitespace separator, including
    // multi-byte whitespace like non-breaking space (\u{a0}).

View on GitHub (pinned to f7330b9ad5)

Solutions

  1. Add a valid variable name before the colon
  2. Ensure the variable prefix character (#, %, @) is immediately followed by the name
  3. Re-type the line cleanly to avoid invisible characters breaking the capture

Example fix

// before
#: cat file.txt
// after
#my-var: cat file.txt
Defensive patterns

Strategy: validation

Validate before calling

let has_var = |line: &str| {
    line.split_once(':').map_or(false, |(lhs, _)| {
        lhs.trim_start_matches(['#', '%', '@']).trim().len() > 0
    })
};
// require has_var(line) before parsing

Prevention

When it happens

Trigger: A line whose shape mostly matches the variable-line pattern but whose variable name position is empty, e.g. an empty name before the colon such as `: cat file.txt` (prefix with no name) or a malformed prefix the regex skipped.

Common situations: Deleting the variable name while editing a config but leaving the `:`; a variable name made only of characters the capture group excludes; truncated first column from a bad copy-paste.

Related errors


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