tinyhumansai/openhuman · error · anyhow::Error

Composio execute failed on v3 ({v3_err}) and v2 fallback ({v

Error message

Composio execute failed on v3 ({v3_err}) and v2 fallback ({v2_err})

What it means

execute_action tries v3 POST execute (carrying connected_account_ref and entity) then falls back to v2 POST /actions/execute; this error means both attempts failed. v3_err is usually the informative half (param validation, expired connected account), with v2 re-expressing the same root cause through the legacy API. Because this is an action execution, callers must not blindly retry — the action may have side effects.

Source

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

        // (`gmail-send-email`) and posted to the wrong `/tools/{slug}/execute`
        // path, so every direct-mode execute 404'd (issue #3219). Pass the
        // action slug through verbatim (trimmed only); the v2 fallback already
        // used the same untransformed name.
        let action_slug = action_name.trim();

        match self
            .execute_action_v3(
                action_slug,
                params.clone(),
                entity_id,
                connected_account_ref,
            )
            .await
        {
            Ok(result) => Ok(result),
            Err(v3_err) => match self.execute_action_v2(action_name, params, entity_id).await {
                Ok(result) => Ok(result),
                Err(v2_err) => anyhow::bail!(
                    "Composio execute failed on v3 ({v3_err}) and v2 fallback ({v2_err})"
                ),
            },
        }
    }

    fn build_execute_action_v3_request(
        action_slug: &str,
        params: serde_json::Value,
        entity_id: Option<&str>,
        connected_account_ref: Option<&str>,
    ) -> (String, serde_json::Value) {
        // POST /api/v3/tools/execute/{ACTION_SLUG} — the action slug stays
        // UPPERCASE_SNAKE (see `execute_action`). Path is `/tools/execute/{slug}`,
        // NOT `/tools/{slug}/execute` (issue #3219).
        let url = format!("{COMPOSIO_API_BASE_V3}/tools/execute/{action_slug}");
        let account_ref = connected_account_ref.and_then(|candidate| {
            let trimmed_candidate = candidate.trim();

View on GitHub (pinned to 7491200858)

Solutions

  1. Read v3_err first — param-validation and connected-account errors surface there with the most detail
  2. Verify the connected account still exists: GET v3 /connected_accounts; if expired, re-run the connect flow to get a fresh OAuth grant
  3. Check the action slug format and casing, and that params match the action's schema
  4. Do NOT auto-retry: executions are not idempotent — only retry after confirming the action did not run (e.g. a send-phase network failure)
Defensive patterns

Strategy: try-catch

Try / catch

match tool.execute_action(slug, params, entity, account).await {
    Ok(result) => Ok(result),
    Err(e) => {
        let msg = format!("{e:#}");
        // NEVER auto-retry: the action may have partially or fully executed.
        if msg.contains("connected") || msg.contains("401") {
            ui.prompt_reconnect(app_for(slug));
        }
        Err(e)
    }
}

Prevention

When it happens

Trigger: Executing a Composio action (e.g. creating an issue) when: the connected account for the app is expired/disconnected (4xx on v3), action params fail validation, the action slug is unknown/wrong-case (v3 uses UPPER_SNAKE like GITHUB_CREATE_ISSUE), the API key is invalid (401), or the network is down.

Common situations: User disconnected the app in Composio but the agent still tries to act; agent invents an action name or passes free-text params; workspace switch invalidated old connected accounts.

Related errors


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