tonhowtf/omniget · error · anyhow::Error

GROK_NO_KEY

GROK_NO_KEY

Error message

GROK_NO_KEY

What it means

ask_xai in the X/Grok tool bails with GROK_NO_KEY when GrokConfig.xai_key is an empty string. The library refuses to call the xAI API without credentials instead of sending a doomed request. It is a pre-flight configuration guard.

Solutions

  1. Set the xAI API key in the config that populates GrokConfig.xai_key (env var or config file) before calling ask().
  2. Verify the key is loaded (non-empty) at startup and fail fast with a clear message if not.
  3. Check that the key is not being trimmed/overwritten to empty by config loading code.

Example fix

// before
let cfg = load_grok_config();
let ans = ask(&cfg, req).await?;
// after
let cfg = load_grok_config();
if cfg.xai_key.is_empty() {
    return Err(anyhow::anyhow!("xAI key missing: set XAI_KEY in config before calling ask"));
}
let ans = ask(&cfg, req).await?;
Defensive patterns

Strategy: validation

Validate before calling

if cfg.xai_key.trim().is_empty() {
    return Err(anyhow::anyhow!("xAI API key not configured (set XAI_KEY)"));
}

Prevention

When it happens

Trigger: Calling ask() which routes to ask_xai while cfg.xai_key is empty — e.g. the Grok config was loaded from a file/env where XAI_KEY was never set, or was set to "".

Common situations: Fresh checkout where the .env/config with the xAI key was never created; CI environment lacking the secret; key intentionally blanked after a rotation failure.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/05f7d5e2323bdfbc. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/x/grok.rs:141

        "x" => "x",
        _ => {
            if !cfg.xai_key.is_empty() {
                "xai"
            } else {
                "x"
            }
        }
    };
    if backend == "xai" {
        ask_xai(&cfg, req).await
    } else {
        ask_x(&cfg, req).await
    }
}

async fn ask_xai(cfg: &GrokConfig, req: GrokRequest) -> anyhow::Result<GrokAnswer> {
    if cfg.xai_key.is_empty() {
        anyhow::bail!("GROK_NO_KEY");
    }
    let model = if req.model.trim().is_empty() {
        cfg.xai_model.clone()
    } else {
        req.model.trim().to_string()
    };
    let mut tools = Vec::new();
    if req.x_search {
        let mut t = json!({ "type": "x_search" });
        let handles: Vec<String> = req
            .handles
            .iter()
            .map(|h| h.trim().trim_start_matches('@').to_string())
            .filter(|h| !h.is_empty())
            .take(20)
            .collect();
        if !handles.is_empty() {
            t["allowed_x_handles"] = json!(handles);

View on GitHub (pinned to 8600b91f42)