{"record":{"id":"cc3e6ad475ee105f","repo":"tinyhumansai/openhuman","slug":"missing-app-or-auth-config-id-for-connect","errorCode":null,"errorMessage":"Missing 'app' or 'auth_config_id' for connect","messagePattern":"Missing 'app' or 'auth_config_id' for connect","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"src/openhuman/integrations/composio/tools/direct.rs","lineNumber":880,"sourceCode":"                        Ok(ToolResult::success(output))\n                    }\n                    Err(e) => Ok(ToolResult::error(format!(\"Action execution failed: {e}\"))),\n                }\n            }\n\n            \"connect\" => {\n                if let Err(error) = self\n                    .security\n                    .enforce_tool_operation(ToolOperation::Act, \"composio.connect\")\n                {\n                    return Ok(ToolResult::error(error));\n                }\n\n                let app = args.get(\"app\").and_then(|v| v.as_str());\n                let auth_config_id = args.get(\"auth_config_id\").and_then(|v| v.as_str());\n\n                if app.is_none() && auth_config_id.is_none() {\n                    anyhow::bail!(\"Missing 'app' or 'auth_config_id' for connect\");\n                }\n\n                match self\n                    .get_connection_url(app, auth_config_id, entity_id)\n                    .await\n                {\n                    Ok(url) => {\n                        let target =\n                            app.unwrap_or(auth_config_id.unwrap_or(\"provided auth config\"));\n                        Ok(ToolResult::success(format!(\n                            \"Open this URL to connect {target}:\\n{url}\"\n                        )))\n                    }\n                    Err(e) => Ok(ToolResult::error(format!(\n                        \"Failed to get connection URL: {e}\"\n                    ))),\n                }\n            }","sourceCodeStart":862,"sourceCodeEnd":898,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/integrations/composio/tools/direct.rs#L862-L898","documentation":"Argument validation in the composio tool's 'connect' dispatch arm: after the security policy approves composio.connect, the call must carry at least one of args['app'] or args['auth_config_id'] — both define what to connect. With neither present the handler bails immediately; note the check treats null/non-string values the same as missing.","triggerScenarios":"Agent or user invokes the composio tool with action='connect' and an args object lacking both keys, e.g. {\"action\":\"connect\"} or {\"action\":\"connect\",\"app\":42} (non-string app is ignored by as_str()).","commonSituations":"LLM omitting required connect parameters; a UI form submitted empty; args key named differently ('toolkit' instead of 'app').","solutions":["Pass a valid toolkit slug: {\"action\":\"connect\",\"app\":\"github\"}","Or pass a specific auth config: {\"action\":\"connect\",\"auth_config_id\":\"ac_...\"}","If the caller meant a different operation, use the supported action names (list, execute, connect) — connect always needs an app or auth_config_id","For agents, include the requirement in the tool prompt so the model supplies 'app' on connect"],"exampleFix":"// before\nlet args = json!({ \"action\": \"connect\" });\n\n// after\nlet args = json!({ \"action\": \"connect\", \"app\": \"github\" });","handlingStrategy":"validation","validationCode":"let app = args.get(\"app\").and_then(|v| v.as_str()).map(str::trim).filter(|s| !s.is_empty());\nlet cfg = args.get(\"auth_config_id\").and_then(|v| v.as_str()).map(str::trim).filter(|s| !s.is_empty());\nif app.is_none() && cfg.is_none() {\n    return Err(anyhow::anyhow!(\"connect requires a non-empty 'app' slug or 'auth_config_id'\"));\n}","typeGuard":"fn has_connect_target(args: &serde_json::Value) -> bool {\n    let pick = |k: &str| args.get(k).and_then(|v| v.as_str()).map(str::trim).is_some_and(|s| !s.is_empty());\n    pick(\"app\") || pick(\"auth_config_id\")\n}","tryCatchPattern":"match tool.execute(json!({\"action\": \"connect\", ...args})).await {\n    Ok(result) => { /* contains the URL to open */ }\n    Err(e) if format!(\"{e:#}\").contains(\"Missing 'app' or 'auth_config_id'\") => {\n        // re-prompt the caller for the target instead of retrying with the same args\n        request_missing_param(\"app\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always construct connect args with an explicit app slug or auth_config_id","State the requirement in agent prompts/tool descriptions so models supply 'app' on connect","Trim and type-check string args before dispatch — non-string values are silently treated as missing"],"tags":["composio","connect","missing-argument","tool-dispatch","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}