{"record":{"id":"803e6fc3a33c433c","repo":"tinyhumansai/openhuman","slug":"composio-connect-failed-on-v3-v3-err-and-v2-fa","errorCode":null,"errorMessage":"Composio connect failed on v3 ({v3_err}) and v2 fallback ({v2_err})","messagePattern":"Composio connect failed on v3 \\((.+?)\\) and v2 fallback \\((.+?)\\)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/integrations/composio/tools/direct.rs","lineNumber":530,"sourceCode":"        &self,\n        app_name: Option<&str>,\n        auth_config_id: Option<&str>,\n        entity_id: &str,\n    ) -> anyhow::Result<String> {\n        let v3 = self\n            .get_connection_url_v3(app_name, auth_config_id, entity_id)\n            .await;\n        match v3 {\n            Ok(url) => Ok(url),\n            Err(v3_err) => {\n                let app = app_name.ok_or_else(|| {\n                    anyhow::anyhow!(\n                        \"Composio v3 connect failed ({v3_err}) and v2 fallback requires 'app'\"\n                    )\n                })?;\n                match self.get_connection_url_v2(app, entity_id).await {\n                    Ok(url) => Ok(url),\n                    Err(v2_err) => anyhow::bail!(\n                        \"Composio connect failed on v3 ({v3_err}) and v2 fallback ({v2_err})\"\n                    ),\n                }\n            }\n        }\n    }\n\n    async fn get_connection_url_v3(\n        &self,\n        app_name: Option<&str>,\n        auth_config_id: Option<&str>,\n        entity_id: &str,\n    ) -> anyhow::Result<String> {\n        let auth_config_id = match auth_config_id {\n            Some(id) => id.to_string(),\n            None => {\n                let app = app_name.ok_or_else(|| {\n                    anyhow::anyhow!(\"Missing 'app' or 'auth_config_id' for v3 connect\")","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/integrations/composio/tools/direct.rs#L512-L548","documentation":"get_connection_url tries v3 connect (app_name or auth_config_id) and falls back to v2 (which requires an app name); this error means both failed. The v3 half usually carries the root cause — unknown toolkit, no auth config for it (see the companion 'No auth config found' error), or 401 — while the v2 half re-fails on the legacy appName route.","triggerScenarios":"Calling connect with an app slug that has no auth config in the Composio workspace; a misspelled/renamed toolkit slug; invalid API key; and the v2 fallback additionally requires 'app', so a v3 failure plus auth_config_id-only input fails v2 for that reason.","commonSituations":"User types a display name ('Google Mail') instead of the toolkit slug ('gmail'); toolkit not yet configured in the Composio workspace; key from a different workspace where the auth config does not exist.","solutions":["Read v3_err — if it says 'No auth config found for toolkit', create the auth config in the Composio dashboard first","Use the exact toolkit slug (e.g. 'github', 'gmail'), not a display name or capitalized variant","Always pass 'app' when calling connect, since the v2 fallback cannot run from auth_config_id alone","Verify the API key and that it belongs to the workspace holding the auth configs"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// The v2 fallback requires `app`; always supply it so a v3 blip can still connect.\nlet app = app.map(str::trim).filter(|a| !a.is_empty());\nif app.is_none() && auth_config_id.is_none() {\n    anyhow::bail!(\"connect requires 'app' or 'auth_config_id'\");\n}\ntool.get_connection_url(app, auth_config_id, &entity).await?;","typeGuard":null,"tryCatchPattern":"match tool.get_connection_url(app, auth_config_id, &entity).await {\n    Ok(url) => ui.open(url),\n    Err(e) => {\n        let msg = format!(\"{e:#}\");\n        if msg.contains(\"No auth config found\") {\n            ui.explain_create_auth_config(app);\n        } else if msg.contains(\"401\") {\n            ui.prompt_reenter_composio_key();\n        }\n    }\n}","preventionTips":["Always pass a canonical lowercase toolkit slug as 'app' — never a display name","Ensure the workspace has an auth config for the toolkit before offering connect in the UI","Pass 'app' even when using auth_config_id-adjacent flows so the v2 fallback remains usable"],"tags":["composio","connect","oauth","fallback-exhausted","auth-config"],"backgroundTag":"upstream-api-fallback-exhausted","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}