{"record":{"id":"32ef3f1b4bcad0d9","repo":"tinyhumansai/openhuman","slug":"backend-error-for-delete","errorCode":null,"errorMessage":"Backend error for DELETE {}: {}","messagePattern":"Backend error for DELETE (.+?): (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/integrations/composio/client.rs","lineNumber":565,"sourceCode":"\n        let envelope: Envelope<T> = resp.json().await?;\n        if !envelope.success {\n            let msg = envelope\n                .error\n                .unwrap_or_else(|| \"unknown backend error\".into());\n            // Mirrors the integrations envelope-error sites — route through\n            // the observability classifier so user-state envelope failures\n            // (composio \"Toolkit X is not enabled\" / \"Trigger type …\n            // not found\" / \"Missing required fields: …\" — OPENHUMAN-TAURI-3R\n            // / -3S / -34 / -97) demote to a breadcrumb instead of firing\n            // a Sentry event. Genuine backend bugs still surface.\n            crate::core::observability::report_error_or_expected(\n                msg.as_str(),\n                \"composio\",\n                \"delete\",\n                &[(\"path\", path), (\"failure\", \"envelope_error\")],\n            );\n            anyhow::bail!(\"Backend error for DELETE {}: {}\", url, msg);\n        }\n        envelope.data.ok_or_else(|| {\n            anyhow::anyhow!(\"Backend returned success but no data for DELETE {}\", url)\n        })\n    }\n}\n\nfn is_post_oauth_auth_readiness_error(resp: &ComposioExecuteResponse) -> bool {\n    if resp.successful {\n        return false;\n    }\n    let Some(error) = resp.error.as_deref() else {\n        return false;\n    };\n    let normalized = error.trim().to_ascii_lowercase();\n    POST_OAUTH_AUTH_ERROR_STRINGS\n        .iter()\n        .any(|needle| normalized.contains(needle))","sourceCodeStart":547,"sourceCodeEnd":583,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/integrations/composio/client.rs#L547-L583","documentation":"The envelope-error twin of the non-2xx case: the DELETE returned 2xx but the parsed {success, data, error} envelope has success=false. The message relays the backend's error string (or \"unknown backend error\"), after routing through the observability classifier so known user-state failures (toolkit not enabled, trigger type not found, missing required fields — the OPENHUMAN-TAURI-3R/-3S/-34/-97 class) demote to breadcrumbs instead of Sentry events.","triggerScenarios":"DELETE /agent-integrations/composio/connections/{id} or /triggers/{id} answering 2xx with {success:false, error:...} — e.g. Composio reporting \"Toolkit X is not enabled\", \"Trigger type ... not found\", or \"Missing required fields\" inside a 200 response.","commonSituations":"Backend started packaging user-state failures in a 2xx envelope; toolkit disabled server-side between listing and deleting; contract change where the error field went missing (message then reads \"unknown backend error\").","solutions":["Read the trailing {msg} — it is the backend's literal error string naming the refused operation","If it says the toolkit/trigger is not enabled or not found, refresh state and stop offering the delete","Capture the raw envelope in debug logging when the message is \"unknown backend error\" to detect contract drift"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.delete_connection(id).await {\n    Ok(resp) => Ok(resp),\n    Err(err) => {\n        let msg = err.to_string();\n        if let Some(rest) = msg.strip_prefix(\"Backend error for DELETE \") {\n            let backend_msg = rest.rsplit(\": \").next().unwrap_or(rest);\n            if backend_msg.contains(\"not enabled\") || backend_msg.contains(\"not found\") {\n                return refresh_connections_and_accept(id); // user-state drift, not a bug\n            }\n        }\n        Err(err)\n    }\n}","preventionTips":["Remember a 2xx status does not mean success — always inspect the envelope's success flag","Handle the known user-state messages (toolkit not enabled / trigger not found / missing fields) as state refreshes, not errors","Log the envelope error verbatim with the path to make classifier tuning possible when new backend messages appear"],"tags":["composio","delete","envelope","backend","api-error"],"backgroundTag":"api-error-response","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}