{"record":{"id":"0f4f144323b5450c","repo":"tinyhumansai/openhuman","slug":"composio-delete-connection-connectionid-must-not","errorCode":null,"errorMessage":"composio.delete_connection: connectionId must not be empty","messagePattern":"composio\\.delete_connection: connectionId must not be empty","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/integrations/composio/client.rs","lineNumber":126,"sourceCode":"                obj.insert(k.clone(), v.clone());\n            }\n        }\n        merge_required_oauth_scopes(&mut body, toolkit)?;\n        self.inner\n            .post::<ComposioAuthorizeResponse>(\"/agent-integrations/composio/authorize\", &body)\n            .await\n    }\n\n    /// `DELETE /agent-integrations/composio/connections/{id}`.\n    ///\n    /// The backend verifies that the caller owns the connection before\n    /// deleting it. We call this via `POST` with a synthetic `_method`\n    /// body because [`IntegrationClient`] does not currently expose a\n    /// generic `delete()` — the backend accepts the method override.\n    pub async fn delete_connection(&self, connection_id: &str) -> Result<ComposioDeleteResponse> {\n        let connection_id = connection_id.trim();\n        if connection_id.is_empty() {\n            anyhow::bail!(\"composio.delete_connection: connectionId must not be empty\");\n        }\n        tracing::debug!(connection_id = %connection_id, \"[composio] delete_connection\");\n        // Fall through to the reusable raw HTTP delete helper below.\n        self.raw_delete::<ComposioDeleteResponse>(&format!(\n            \"/agent-integrations/composio/connections/{connection_id}\"\n        ))\n        .await\n    }\n\n    // ── Tools ───────────────────────────────────────────────────────\n\n    /// `GET /agent-integrations/composio/tools?toolkits=<csv>&tags=<csv>` — fetch\n    /// OpenAI function-calling schemas. Omit `toolkits` to get every enabled\n    /// toolkit's tools. `tags` narrows by Composio action tag (OR semantics —\n    /// multiple tags broaden the result).\n    pub async fn list_tools(\n        &self,\n        toolkits: Option<&[String]>,","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/integrations/composio/client.rs#L108-L144","documentation":"ComposioClient::delete_connection rejects a connectionId that is empty after trimming, before issuing DELETE /agent-integrations/composio/connections/{id}. The id must come from a previous authorize or list_connections result; the guard stops a meaningless DELETE against the bare /connections/ URL.","triggerScenarios":"Calling delete_connection(\"\") or with a whitespace-only id — usually a delete fired from a UI row whose connection id field was never populated, or a flow that deletes before fetching connections.","commonSituations":"Frontend row model missing the id mapping; deleting from a stale/empty connections list; race where the row was cleared before the delete handler ran.","solutions":["Fetch the connection list first and delete by an id taken from it","Make the id a required parameter in the calling RPC/UI path so an empty value is caught with a better message","Disable the delete action in the UI when the row has no id"],"exampleFix":"// before\nclient.delete_connection(conn.id.as_deref().unwrap_or(\"\")).await?;\n\n// after\nlet Some(id) = conn.id.as_deref().map(str::trim).filter(|s| !s.is_empty()) else {\n    anyhow::bail!(\"connection has no id; refresh the connection list\");\n};\nclient.delete_connection(id).await?;","handlingStrategy":"validation","validationCode":"let Some(id) = connection_id.as_deref().map(str::trim).filter(|s| !s.is_empty()) else {\n    anyhow::bail!(\"connection id is required to delete a connection\");\n};\nclient.delete_connection(id).await?;","typeGuard":"fn is_non_empty_id(s: &str) -> bool {\n    !s.trim().is_empty()\n}","tryCatchPattern":null,"preventionTips":["Source connection ids only from list_connections/authorize responses","Disable delete actions in the UI until the row has a populated id","Type connection ids as NonEmptyString-style wrappers at the boundary if your codebase supports it"],"tags":["composio","connections","validation","empty-string","argument-validation"],"backgroundTag":"empty-string-argument","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}