tinyhumansai/openhuman · error · anyhow::Error
Composio v3 connected_accounts failed: {err}
Error message
Composio v3 connected_accounts failed: {err} What it means
Non-2xx from GET v3 /connected_accounts (limit=200) — the core call of the direct-mode connection poller behind direct_list_connections. response_error folds status + body into {err}. A 401 'Invalid API key' here is exactly what feeds the consecutive-failure breaker; after enough repetitions the poller stops calling and surfaces the backoff message instead.
Source
Thrown at src/openhuman/integrations/composio/tools/direct.rs:645
let url = format!("{}/connected_accounts", self.base_v3);
self.ensure_request_url(&url)?;
let resp = self
.client()
.get(&url)
.header("x-api-key", &self.api_key)
// Composio paginates; pull a generous page size so most
// users see their full list in one round trip. If a user has
// > 200 connected accounts (extremely rare for an individual
// tenant) the rest will be missing until we add explicit
// pagination — note for the follow-up.
.query(&[("limit", "200")])
.send()
.await?;
if !resp.status().is_success() {
let err = response_error(resp).await;
anyhow::bail!("Composio v3 connected_accounts failed: {err}");
}
let mut body: ComposioConnectedAccountsResponse = resp
.json()
.await
.context("Failed to decode Composio v3 connected_accounts response")?;
// Drop rows with a blank id — serde_default means id can be ""
// if the upstream response is malformed. An empty connectionId
// propagated downstream causes invalid v3 API calls.
body.items.retain(|item| !item.id.trim().is_empty());
tracing::debug!(
count = body.items.len(),
"[composio-direct] list_connected_accounts: fetched connected accounts"
);
Ok(body.items)
}
async fn resolve_auth_config_id(&self, app_name: &str) -> anyhow::Result<String> {View on GitHub (pinned to 7491200858)
Solutions
- Inspect {err}: 401 → re-enter a valid key in Connections > Composio; 429 → lengthen the poll interval; 5xx → wait and retry
- Verify the key with curl -H 'x-api-key: <key>' https://backend.composio.dev/api/v3/connected_accounts
- If you administrate the poller, honor the direct_auth backoff gate instead of hammering through 401s
Defensive patterns
Strategy: try-catch
Try / catch
let key_id = tool.auth_key_fingerprint();
if let Some(gate) = direct_auth::direct_auth_backoff_error(key_id) {
return Err(anyhow::anyhow!(gate));
}
match tool.list_connected_accounts().await {
Ok(items) => { direct_auth::record_direct_auth_success(key_id); Ok(items) }
Err(e) => {
let rendered = format!("{e:#}");
if let direct_auth::DirectAuthFailureDecision::CircuitOpened { consecutive } =
direct_auth::record_direct_auth_failure(key_id, &rendered)
{ return Err(anyhow::anyhow!(direct_auth::invalid_api_key_backoff_message(consecutive))); }
Err(e)
}
} Prevention
- Route every direct connected_accounts call through the direct_auth recorder so 401s actually trip the breaker
- Lengthen poll intervals to stay clear of 429s with 200-account pages
- Degrade the connections UI to the last known list during transient 5xx instead of showing an error storm
When it happens
Trigger: 401 invalid API key (drives errors 280/281); 429 from polling too aggressively; 5xx during a Composio incident; malformed upstream body is a separate decode error — this one is purely the HTTP status branch.
Common situations: Revoked key while the poller keeps running; many accounts and tight poll interval hitting the limit page; transient Composio errors during deploys.
Related errors
- Composio v3 API error: {err}
- Composio v3 list_tool_schemas: {err}
- Composio v3 action execution failed: {err}
- Composio v3 connect failed: {err}
- Composio v3 auth config lookup failed: {err}
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/0e0e9fd92e6fa0eb.
Report an issue: GitHub.