helix-editor/helix · error · anyhow::Error

unknown variable '{}'

Error message

unknown variable '{}'

What it means

expand() handles command-line tokens like %{name}; it resolves the inner name through Variable::from_name, which only knows the built-in variables: cursor_line, cursor_column, buffer_name, file_path_absolute, line_ending, current_working_directory, workspace_directory, language, selection, selection_line_start, selection_line_end. An unknown name produces "unknown variable '{name}'".

Source

Thrown at helix-view/src/expansion.rs:112

            "selection" => Some(Self::Selection),
            "selection_line_start" => Some(Self::SelectionLineStart),
            "selection_line_end" => Some(Self::SelectionLineEnd),
            _ => None,
        }
    }
}

/// Expands the given command line token.
///
/// Note that the lifetime of the expanded variable is only bound to the input token and not the
/// `Editor`. See `expand_variable` below for more discussion of lifetimes.
pub fn expand<'a>(editor: &Editor, token: Token<'a>) -> Result<Cow<'a, str>> {
    // Note: see the `TokenKind` documentation for more details on how each branch should expand.
    match token.kind {
        TokenKind::Unquoted | TokenKind::Quoted(_) => Ok(token.content),
        TokenKind::Expansion(ExpansionKind::Variable) => {
            let var = Variable::from_name(&token.content)
                .ok_or_else(|| anyhow!("unknown variable '{}'", token.content))?;

            expand_variable(editor, var)
        }
        TokenKind::Expansion(ExpansionKind::Unicode) => {
            if let Some(ch) = u32::from_str_radix(token.content.as_ref(), 16)
                .ok()
                .and_then(char::from_u32)
            {
                Ok(Cow::Owned(ch.to_string()))
            } else {
                Err(anyhow!(
                    "could not interpret '{}' as a Unicode character code",
                    token.content
                ))
            }
        }
        TokenKind::Expand => expand_inner(editor, token.content),
        TokenKind::Expansion(ExpansionKind::Shell) => expand_shell(editor, token.content),

View on GitHub (pinned to 079a789e8c)

Solutions

  1. Use one of the documented names: cursor_line, cursor_column, buffer_name, file_path_absolute, line_ending, current_working_directory, workspace_directory, language, selection, selection_line_start, selection_line_end.
  2. Check book/src/command-line.md (the Variable list lives there and in Variable::VARIANTS) for your Helix version.
  3. For shell/env data, use the shell expansion (%sh{...}) instead of an undefined variable.

Example fix

# before
 :echo %{cursorline}

# after
 :echo %{cursor_line}
Defensive patterns

Strategy: validation

Validate before calling

let name = token_content; // text between %{ ... }
if Variable::from_name(name).is_none() {
    return Err(anyhow!(
        "unknown variable '{name}'; known: {:?}",
        Variable::VARIANTS.iter().map(|v| v.as_str()).collect::<Vec<_>>()
    ));
}
expand(editor, token)?;

Type guard

fn known_variable(s: &str) -> Option<Variable> {
    Variable::from_name(s)
}

Try / catch

match expand(editor, token) {
    Ok(v) => { /* use v */ }
    Err(err) if err.to_string().contains("unknown variable") => {
        // degrade gracefully: keep the literal text instead of failing the command
        Ok(Cow::Borrowed(token.content))
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Typing :echo %{linenumber} or any %{...} whose content is not exactly one of the eleven built-in names; passing unvalidated user input as a variable expansion; using a name added in a newer Helix version against an older build (or vice versa).

Common situations: Typos and snake_case mistakes (cursorLine vs cursor_line); assuming arbitrary editor state (like %{register} or %{mode}) is available as a variable; feature-drift between Helix versions where the variable list changed.

Related errors


AI-assisted analysis of helix-editor/helix@079a789e8c (2026-08-16). Data as JSON: /api/errors/b279b3cb69501569. Report an issue: GitHub.