{"record":{"id":"a63e15358d51cc11","repo":"tinyhumansai/openhuman","slug":"failed-to-fetch-repositories","errorCode":null,"errorMessage":"Failed to fetch repositories","messagePattern":"Failed to fetch repositories","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/components/skills/SmartIssuePicker.tsx","lineNumber":93,"sourceCode":"  // each onRepoSelect captures its own id and bails out of any state\n  // update once a newer selection has superseded it.\n  const selectionSeqRef = useRef(0);\n\n  // ── Load repos via Composio ─────────────────────────────────────────\n  const loadRepos = useCallback(async () => {\n    setReposLoading(true);\n    setReposError(null);\n    try {\n      const connections = await listConnections();\n      const ghConn = connections.connections?.find(\n        c =>\n          c.toolkit.toLowerCase().includes('github') &&\n          (c.status === 'ACTIVE' || c.status === 'CONNECTED')\n      );\n      if (!ghConn) throw new Error('NOT_CONNECTED');\n\n      const res = await composioExecute('GITHUB_LIST_REPOSITORIES_FOR_THE_AUTHENTICATED_USER', {});\n      if (!res.successful) throw new Error(res.error ?? 'Failed to fetch repositories');\n\n      const raw = res.data;\n      let repoList: ComposioGhRepo[] = [];\n      const items = Array.isArray(raw)\n        ? raw\n        : ((raw as Record<string, unknown>)?.repositories ?? []);\n      if (Array.isArray(items)) {\n        repoList = (items as Record<string, unknown>[]).map(r => ({\n          owner: String((r.owner as Record<string, unknown>)?.login ?? r.owner ?? ''),\n          repo: String(r.name ?? ''),\n          fullName: String(\n            r.full_name ?? `${(r.owner as Record<string, unknown>)?.login ?? r.owner}/${r.name}`\n          ),\n          private: r.private as boolean | undefined,\n          defaultBranch: r.default_branch as string | undefined,\n        }));\n      }\n","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/components/skills/SmartIssuePicker.tsx#L75-L111","documentation":"SmartIssuePicker repo loading: after confirming a GitHub connection exists in listConnections() (ACTIVE/CONNECTED, toolkit contains 'github' - otherwise the distinct 'NOT_CONNECTED' error throws earlier), it runs composioExecute('GITHUB_LIST_REPOSITORIES_FOR_THE_AUTHENTICATED_USER', {}). If the Composio action returns successful:false, it throws res.error when present, else this fallback string. The subsequent parsing handles array or {repositories:[]} response shapes.","triggerScenarios":"The Composio GitHub action itself fails: revoked/expired GitHub token on the connection, GitHub API error or rate limit, Composio-side outage, or the connected account lacking repo read scope.","commonSituations":"Token revoked in GitHub settings while Composio still lists the connection ACTIVE; secondary rate limits hitting bulk repo listing; org SSO not authorized for the token; intermittent Composio 5xx surfacing as successful:false with no error string.","solutions":["Reconnect GitHub via Connections so Composio gets a fresh token","Log or inspect res.error - when the fallback fires it means Composio returned no error detail at all","Retry after a minute if rate limiting is plausible","Confirm the account actually grants repository read access (enterprise/SSO auth)"],"exampleFix":"// before\nif (!res.successful) throw new Error(res.error ?? 'Failed to fetch repositories');\n\n// after - keep NOT_CONNECTED distinct and surface Composio's detail when it exists\nif (!res.successful) {\n  const detail = res.error ?? 'Failed to fetch repositories';\n  throw new Error(`Composio GITHUB_LIST_REPOSITORIES: ${detail}`);\n}","handlingStrategy":"try-catch","validationCode":"// Check the connection before loading, so NOT_CONNECTED and action failure stay distinct\nconst conns = await listConnections();\nconst gh = conns.connections?.find(c =>\n  c.toolkit.toLowerCase().includes('github') &&\n  (c.status === 'ACTIVE' || c.status === 'CONNECTED'));\nif (!gh) { setReposError('Connect GitHub first'); return; }","typeGuard":null,"tryCatchPattern":"try {\n  const res = await composioExecute('GITHUB_LIST_REPOSITORIES_FOR_THE_AUTHENTICATED_USER', {});\n  if (!res.successful) throw new Error(res.error ?? 'Failed to fetch repositories');\n  // parse res.data ...\n} catch (err) {\n  const msg = err instanceof Error ? err.message : String(err);\n  if (msg === 'NOT_CONNECTED') setReposError('Connect GitHub in Connections first');\n  else setReposError(msg);\n}","preventionTips":["Keep the GitHub Composio connection fresh - an ACTIVE status does not prove the token still works","Always fall back to res.error; the generic string only fires when Composio returned no detail","Handle NOT_CONNECTED separately so users get a 'connect first' message, not a fetch failure"],"tags":["composio","github","repositories","integration","skills"],"backgroundTag":"third-party-integration-action-failed","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}