tinyhumansai/openhuman · error · anyhow::Error

composio direct api key must not be empty

Error message

composio direct api key must not be empty

What it means

create_direct_composio_tool_for_api_key builds the direct-to-Composio (non-backend-proxied) tool from a user-supplied API key; a key that is empty after trimming is rejected before any client is constructed. The guard sits at factory time so direct mode never starts with a credential that cannot work.

Source

Thrown at src/openhuman/integrations/composio/client.rs:730

/// HMAC-verified trigger fan-out, no `/agent-integrations/pricing`),
/// so most existing call-sites continue to use `Backend` for now.
/// Direct-mode integration of the full surface (especially trigger
/// webhooks) is a follow-up.
pub enum ComposioClientKind {
    Backend(ComposioClient),
    /// Held inside an `Arc` so the variant stays cheap to clone — this
    /// matches the rest of the tool registry which juggles
    /// `Arc<dyn Tool>` for the same direct-mode tool elsewhere.
    Direct(Arc<crate::openhuman::tools::ComposioTool>),
}

pub(crate) fn create_direct_composio_tool_for_api_key(
    config: &crate::openhuman::config::Config,
    api_key: &str,
) -> anyhow::Result<Arc<crate::openhuman::tools::ComposioTool>> {
    let api_key = api_key.trim();
    if api_key.is_empty() {
        anyhow::bail!("composio direct api key must not be empty");
    }

    // The direct client takes a `SecurityPolicy` for `Tool::execute`
    // gating, but the factory's job is only to materialize a *client*
    // — it does not actually invoke `execute()` itself, so the
    // default policy is sufficient here. Callers that go through
    // the `Tool` surface re-acquire the live policy from their own
    // context.
    let security = Arc::new(crate::openhuman::security::SecurityPolicy::default());
    #[cfg(debug_assertions)]
    let tool = match (
        std::env::var("OPENHUMAN_COMPOSIO_DIRECT_BASE_V2").ok(),
        std::env::var("OPENHUMAN_COMPOSIO_DIRECT_BASE_V3").ok(),
    ) {
        (Some(base_v2), Some(base_v3)) => {
            crate::openhuman::tools::ComposioTool::new_with_base_urls_for_loopback(
                api_key,
                Some(config.composio.entity_id.as_str()),

View on GitHub (pinned to 7491200858)

Solutions

  1. Set the real Composio API key in the config/environment before enabling direct mode
  2. Validate the key non-empty at config-load time with a message naming the exact setting, instead of failing later at tool creation
  3. If the key is genuinely absent, stay on the backend-proxied path rather than selecting direct mode

Example fix

// before
let tool = create_direct_composio_tool_for_api_key(&config, cfg.composio_api_key.as_str()).await?;

// after — validate at config load with a named setting
let key = cfg.composio_api_key.trim();
if key.is_empty() {
    anyhow::bail!("composio direct mode requires composio_api_key to be set");
}
let tool = create_direct_composio_tool_for_api_key(&config, key)?;
Defensive patterns

Strategy: validation

Validate before calling

let api_key = cfg.composio_api_key.trim();
if api_key.is_empty() {
    anyhow::bail!(
        "composio direct mode requires a non-empty API key (setting: composio_api_key / env var)"
    );
}
let tool = create_direct_composio_tool_for_api_key(&config, api_key)?;

Type guard

fn api_key_present(cfg: &Config) -> bool {
    !cfg.composio_api_key.trim().is_empty()
}

Prevention

When it happens

Trigger: Direct Composio mode enabled while the configured api_key is empty or whitespace — e.g. the key env var unset in CI but the config still selects direct mode, or a blank key saved from settings.

Common situations: Environment variable for the key missing in CI/containers; UI allowed saving an empty key; key field contains only whitespace from a bad copy/paste; config default of "" left in place.

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 tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/8fb409c06c54a329. Report an issue: GitHub.