tinyhumansai/openhuman · error

Exa search unavailable: no API key configured. Add your Exa

Error message

Exa search unavailable: no API key configured. Add your Exa API key under Connections > Search engine, set EXA_API_KEY or OPENHUMAN_EXA_API_KEY, or add search.exa.api_key to config.toml.

What it means

Error "Exa search unavailable: no API key configured. Add your Exa API key under Connections > Search engine, set EXA_API_KEY or OPENHUMAN_EXA_API_KEY, or add search.exa.api_key to config.toml." thrown in tinyhumansai/openhuman.

Source

Thrown at src/openhuman/search/tools/exa.rs:179

    }

    /// Privacy epic S7 (#4441): under `LocalOnly` the search is refused before
    /// anything reaches Exa. Returns the `[policy-blocked]` tool result to hand
    /// straight back from `execute`, or `None` when the transfer is permitted.
    fn local_only_block(&self) -> Option<ToolResult> {
        crate::openhuman::security::egress::local_only_tool_block(&self.egress_descriptor())
            .map(ToolResult::error)
    }

    /// The configured key, or a user-actionable error naming exactly where to
    /// set it. Surfaced verbatim on the first search attempt.
    fn key(&self) -> anyhow::Result<&str> {
        self.api_key
            .as_deref()
            .map(str::trim)
            .filter(|k| !k.is_empty())
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "Exa search unavailable: no API key configured. Add your Exa API key \
                     under Connections > Search engine, set EXA_API_KEY or \
                     OPENHUMAN_EXA_API_KEY, or add search.exa.api_key to config.toml."
                )
            })
    }

    /// Requested result count, honouring both `max_results` and Exa's native
    /// `numResults` spelling. An explicit per-call value is clamped to the
    /// API's own 1..=20 range rather than to the configured `max_results` --
    /// config supplies the *default* when the call omits one, and a caller may
    /// ask for more (this matches `querit.rs`).
    fn requested_results(&self, args: &Value) -> usize {
        args.get("max_results")
            .or_else(|| args.get("num_results"))
            .or_else(|| args.get("numResults"))
            .and_then(Value::as_u64)
            .map(|n| n.clamp(1, 20) as usize)

View on GitHub (pinned to 7491200858)

Solutions

  1. Add the Exa API key in the app: Connections > Search engine.
  2. Set the EXA_API_KEY or OPENHUMAN_EXA_API_KEY environment variable.
  3. Add search.exa.api_key to config.toml and restart the core.
  4. Fall back to another configured search provider (Brave, Parallel) if immediate Exa setup is not possible.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at src/openhuman/search/tools/exa.rs:179 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/68d20b0c1040b329. Report an issue: GitHub.