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

Unknown key `{}`

Error message

Unknown key `{}`

What it means

`:get <key>` serializes the live editor config to JSON and resolves the (lowercased) dotted key as a JSON pointer ('/a/b'). Any path that does not exist in the serialized config — wrong name, wrong path segment, or a key from a different helix version — returns 'Unknown key `x`'. No state is changed; it is a read-only lookup.

Source

Thrown at helix-term/src/commands/typed.rs:2267

        // When a user hits backspace and there are no numbers left,
        // we can bring them back to their original selection. If they
        // begin typing numbers again, we'll start a new preview session.
        PromptEvent::Update if args.is_empty() => abort_goto_line_number_preview(cx),
        PromptEvent::Update => update_goto_line_number_preview(cx, args)?,
    }

    Ok(())
}

// Fetch the current value of a config option and output as status.
fn get_option(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    let key = &args[0].to_lowercase();
    let key_error = || anyhow::anyhow!("Unknown key `{}`", key);

    let config = serde_json::json!(cx.editor.config().deref());
    let pointer = format!("/{}", key.replace('.', "/"));
    let value = config.pointer(&pointer).ok_or_else(key_error)?;

    cx.editor.set_status(value.to_string());
    Ok(())
}

/// Change config at runtime. Access nested values by dot syntax, for
/// example to disable smart case search, use `:set search.smart-case false`.
fn set_option(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> {
    if event != PromptEvent::Validate {
        return Ok(());
    }

    let (key, arg) = (&args[0].to_lowercase(), args[1].trim());

View on GitHub (pinned to 079a789e8c)

Solutions

  1. Copy the exact dotted path from the config documentation — the same names config.toml uses (e.g. `:get search.smart-case`).
  2. Query parent keys stepwise (`:get search`) to discover the existing subtree.
  3. Use `:config-open` to see a config with valid keys side by side.

Example fix

# before
:get smartcase
# after
:get search.smart-case
Defensive patterns

Strategy: validation

Validate before calling

// same resolution :get uses — probe the pointer before reading
let cfg = serde_json::json!(editor.config().deref());
let pointer = format!("/{}", key.to_lowercase().replace('.', "/"));
if cfg.pointer(&pointer).is_none() { /* unknown key: reject early */ }

Type guard

fn config_key_exists(editor: &Editor, key: &str) -> bool {
    let cfg = serde_json::json!(editor.config().deref());
    cfg.pointer(&format!("/{}", key.to_lowercase().replace('.', "/"))).is_some()
}

Prevention

When it happens

Trigger: `:get bogus`, `:get lsp.bogus`, or a key valid in another helix version; also wrong path segment order like `:get smart-case.search`.

Common situations: Guessing key names instead of copying from the config reference; version drift after an upgrade renamed/moved keys; typos.

Related errors


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