tinyhumansai/openhuman · error · anyhow::Error

Composio v3 action execution failed: {err}

Error message

Composio v3 action execution failed: {err}

What it means

Non-2xx from the v3 action-execution POST. The request body is built by build_execute_action_v3_request (action slug, params, entity_id, connected_account_ref) and the URL passes ensure_request_url; response_error folds status + body into {err}. This is the primary execution path — the v2 fallback only runs after this already failed.

Source

Thrown at src/openhuman/integrations/composio/tools/direct.rs:462

            params,
            entity_id,
            connected_account_ref,
        );
        let url = format!("{}/tools/execute/{action_slug}", self.base_v3);

        self.ensure_request_url(&url)?;

        let resp = self
            .client()
            .post(&url)
            .header("x-api-key", &self.api_key)
            .json(&body)
            .send()
            .await?;

        if !resp.status().is_success() {
            let err = response_error(resp).await;
            anyhow::bail!("Composio v3 action execution failed: {err}");
        }

        let result: serde_json::Value = resp
            .json()
            .await
            .context("Failed to decode Composio v3 execute response")?;
        Ok(result)
    }

    async fn execute_action_v2(
        &self,
        action_name: &str,
        params: serde_json::Value,
        entity_id: Option<&str>,
    ) -> anyhow::Result<serde_json::Value> {
        let url = format!("{}/actions/{action_name}/execute", self.base_v2);

        let mut body = json!({

View on GitHub (pinned to 7491200858)

Solutions

  1. Inspect {err} — Composio's body names the exact invalid field or missing account
  2. Re-authenticate the app via the connect flow if the connected account is expired/absent
  3. Match the action slug exactly (v3 UPPER_SNAKE) and validate params against the tool schema from list_tool_schemas_v3
  4. 429/5xx: retry with backoff only when safe
Defensive patterns

Strategy: try-catch

Try / catch

match tool.execute_action_v3_path(slug, params, entity, account).await {
    Ok(v) => Ok(v),
    Err(e) => {
        let msg = format!("{e:#}");
        if msg.contains("400") || msg.contains("422") {
            return Err(anyhow::anyhow!("invalid params for {slug}: {msg}")); // not retryable
        }
        Err(e)
    }
}

Prevention

When it happens

Trigger: 4xx param validation failures; expired or deleted connectedAccount referenced by connected_account_ref; unknown/wrong-case action slug; 401 invalid API key; 429/5xx. Example: executing with a disconnected account yields a 4xx explaining the missing connected account.

Common situations: Agent passes user-derived strings as params without matching the action schema; connected account revoked upstream; slug casing copied from v2 docs.

Related errors


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