{"record":{"id":"d98a6bb5c426f49d","repo":"tinyhumansai/openhuman","slug":"gmail-fetch-emails-error-err","errorCode":null,"errorMessage":"GMAIL_FETCH_EMAILS error: {err}","messagePattern":"GMAIL_FETCH_EMAILS error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/learning/linkedin_enrichment.rs","lineNumber":555,"sourceCode":"        ComposioClientKind::Direct(direct) => {\n            tracing::debug!(\n                \"[linkedin_enrichment][composio-direct] GMAIL_FETCH_EMAILS via direct tenant\"\n            );\n            direct_execute(\n                direct,\n                \"GMAIL_FETCH_EMAILS\",\n                Some(args),\n                &config.composio.entity_id,\n                None,\n            )\n            .await\n            .map_err(|e| anyhow::anyhow!(\"GMAIL_FETCH_EMAILS (direct) failed: {e:#}\"))?\n        }\n    };\n\n    if !resp.successful {\n        let err = resp.error.unwrap_or_else(|| \"unknown error\".into());\n        anyhow::bail!(\"GMAIL_FETCH_EMAILS error: {err}\");\n    }\n\n    // Walk the messages, decode HTML parts, and search for profile URLs.\n    let messages = resp\n        .data\n        .get(\"messages\")\n        .and_then(|v| v.as_array())\n        .cloned()\n        .unwrap_or_default();\n\n    for msg in &messages {\n        // Collect all text to search: plain messageText + decoded HTML parts.\n        let mut searchable = String::new();\n\n        // Plain text body (already decoded by Composio).\n        if let Some(text) = msg.get(\"messageText\").and_then(|v| v.as_str()) {\n            searchable.push_str(text);\n            searchable.push('\\n');","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/agent/learning/linkedin_enrichment.rs#L537-L573","documentation":"The LinkedIn enrichment flow executes the Composio GMAIL_FETCH_EMAILS action (via the standard path or the direct fallback); the action completed at transport level but its response carried successful=false, and the response's error string ('unknown error' when absent) is bailed with the GMAIL_FETCH_EMAILS prefix. This is the integration or backend rejecting or failing the action - not a network failure in this client, which surfaces a different message for the direct path.","triggerScenarios":"The user's Composio Gmail connection expired or was revoked; config.composio.entity_id is stale or wrong; quota or timeout inside Composio or upstream Gmail; the action arguments were rejected by the integration.","commonSituations":"A user disconnected Gmail after onboarding and the enrichment flow still runs; a stale composio.entity_id after workspace changes; large mailboxes timing out the fetch.","solutions":["Read the embedded error text - it is Composio's own failure reason.","Verify the Composio connection state and re-authenticate Gmail if expired.","Confirm config.composio.entity_id points at the right entity.","For transient upstream failures retry later; narrow the fetch window if timeouts recur."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"Wrap the enrichment call; on failure log a warning with the embedded Composio error and continue the flow without enrichment data - the LinkedIn enrichment is best-effort and should not abort the surrounding operation.","preventionTips":["Pre-check the Composio connection state and config.composio.entity_id before starting enrichment.","Surface re-auth prompts when the error text indicates an expired Gmail connection.","Cap the fetch window so large mailboxes do not time out the action."],"tags":["composio","gmail","integration","enrichment","third-party-api"],"backgroundTag":"third-party-api-error","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}