{"record":{"id":"1a7f70c5e658fa84","repo":"zeroclaw-labs/zeroclaw","slug":"composio-v3-action-execution-failed-err","errorCode":null,"errorMessage":"Composio v3 action execution failed: {err}","messagePattern":"Composio v3 action execution failed: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/composio.rs","lineNumber":398,"sourceCode":"            params,\n            text,\n            entity_id,\n            connected_account_ref,\n        );\n\n        ensure_https(&url)?;\n\n        let resp = self\n            .client()\n            .post(&url)\n            .header(\"x-api-key\", &self.api_key)\n            .json(&body)\n            .send()\n            .await?;\n\n        if !resp.status().is_success() {\n            let err = response_error(resp).await;\n            anyhow::bail!(\"Composio v3 action execution failed: {err}\");\n        }\n\n        let result: serde_json::Value = resp\n            .json()\n            .await\n            .context(\"Failed to decode Composio v3 execute response\")?;\n        Ok(result)\n    }\n\n    /// Get the OAuth connection URL for a specific app/toolkit or auth config.\n    /// Uses the v3 endpoint.\n    pub async fn get_connection_url(\n        &self,\n        app_name: Option<&str>,\n        auth_config_id: Option<&str>,\n        entity_id: &str,\n    ) -> anyhow::Result<ComposioConnectionLink> {\n        self.get_connection_url_v3(app_name, auth_config_id, entity_id)","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/composio.rs#L380-L416","documentation":"The per-attempt HTTP failure underneath the aggregated execute errors: POST {COMPOSIO_API_BASE_V3}/tools/execute/{slug} with body {version: latest, arguments|text, user_id?, connected_account_id?} returned a non-2xx status. response_error() formats the status plus Composio's error message with account/entity IDs redacted and a 240-char cap. Each such failure is collected by execute_action into the 'slug: <this message>' entries of the 1132/1133 aggregation, so end users normally see it embedded there.","triggerScenarios":"404: the slug candidate is not a real v3 tool; 400: arguments fail the tool's input schema (missing or invalid fields); 401: bad x-api-key; 403: workspace lacks the app; 429: rate limit; 5xx: backend error. Also 4xx when the connected account is missing or its OAuth token expired for the entity.","commonSituations":"Legacy uppercase action names (e.g. GITHUB_LIST_REPOS) tried against v3 slugs; params built from an outdated schema; API key from a different workspace; OAuth token expired since the last successful run.","solutions":["Decode the embedded 'HTTP <code>': 404 -> get the exact slug via action='list'; 400 -> fix params per the schema hint; 401 -> fix composio.api_key; 429 -> back off.","Pin the exact tool_slug so only one candidate is attempted.","Verify the account with action='list_accounts' and pass connected_account_id.","Re-run action='connect' if the account's OAuth token expired."],"exampleFix":"// before: legacy alias + guessed params\nlet args = json!({\"action\": \"execute\", \"action_name\": \"GITHUB_LIST_REPOS\", \"params\": {}});\n\n// after: exact v3 slug (lowercase, hyphenated) from action='list' + required params\nlet args = json!({\"action\": \"execute\", \"tool_slug\": \"github-list-repositories\", \"params\": {\"owner\": \"zeroclaw\"}});","handlingStrategy":"try-catch","validationCode":"// Resolve the slug from the catalog and validate params before executing\nlet actions = tool.list_actions(app).await?;\nif !actions.iter().any(|a| a.name == requested_slug) {\n    anyhow::bail!(\"slug '{requested_slug}' not in app catalog; pick from action='list'\");\n}","typeGuard":"fn extract_composio_status(err: &str) -> Option<u16> {\n    let idx = err.find(\"HTTP \")?;\n    err[idx + 5..]\n        .split(|c: char| !c.is_ascii_digit())\n        .next()\n        .and_then(|digits| digits.parse().ok())\n}","tryCatchPattern":"// Do NOT blind-retry executes: they can have side effects (send an email twice).\nmatch tool.execute(args).await {\n    Ok(r) if r.success => {}\n    Ok(r) => match extract_composio_status(&r.error.clone().unwrap_or_default()) {\n        Some(429) | Some(500..=599) => { /* safe to retry once after backoff */ }\n        _ => { /* inspect per-slug errors; fix params/slug/account */ }\n    },\n    Err(e) => { /* transport failure */ }\n}","preventionTips":["Treat 4xx as permanent (fix inputs); only 429/5xx are retryable","Never auto-retry side-effecting actions without idempotency knowledge","Keep a slug cache from action='list' to avoid 404 candidates"],"tags":["composio","rust","http","execute","params"],"backgroundTag":"api-request-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}