{"record":{"id":"7a5150be03800035","repo":"paperclipai/paperclip","slug":"slack-inventory-failed-body-error-unknown-e","errorCode":null,"errorMessage":"Slack inventory failed: ${body.error ?? \"unknown error\"}","messagePattern":"Slack inventory failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/chat-provider-inventory.ts","lineNumber":92,"sourceCode":"    const response = await input.fetch(url, {\n      headers: { authorization: `Bearer ${input.botToken}` },\n      signal: slackRequestSignal(),\n    });\n    const body = await jsonResponse<{\n      ok?: boolean;\n      error?: string;\n      channels?: Array<{\n        id?: string;\n        name?: string;\n        is_member?: boolean;\n        is_private?: boolean;\n        is_archived?: boolean;\n        context_team_id?: string;\n      }>;\n      response_metadata?: { next_cursor?: string };\n    }>(response, \"Slack\");\n    if (!body.ok)\n      throw new Error(\n        `Slack inventory failed: ${body.error ?? \"unknown error\"}`,\n      );\n    for (const channel of body.channels ?? []) {\n      if (!channel.id || !channel.is_member || channel.is_archived) continue;\n      resources.push({\n        providerResourceId: channel.id,\n        type: \"channel\",\n        label: channel.name ? `#${channel.name}` : channel.id,\n        metadata: {\n          private: channel.is_private === true,\n          ...(channel.context_team_id\n            ? { contextTeamId: channel.context_team_id }\n            : {}),\n          source: \"provider_inventory\",\n        },\n      });\n    }\n    cursor = body.response_metadata?.next_cursor?.trim() ?? \"\";","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-provider-inventory.ts#L74-L110","documentation":"Thrown by listSlackBotChannels when Slack's conversations.list responds with ok:false — Slack's standard envelope for a failed API call. The thrown message includes body.error (Slack's machine-readable error code like 'invalid_auth', 'missing_scope', 'ratelimited') or 'unknown error' if absent. Only channels where the bot is an active member are listed, so this error concerns the API call itself, not the filtering.","triggerScenarios":"Slack conversations.list returns {ok:false,...}: invalid_auth (bad/expired bot token), missing_scope (bot lacks channels:read/groups:read), ratelimited, or any other Slack error code.","commonSituations":"Bot token rotated or revoked by a Slack admin; app reinstalled without read scopes; bulk inventory scans triggering Slack's tier-based rate limits; workspace app restrictions.","solutions":["Read the Slack error code in the message and act on it (invalid_auth -> reconnect, missing_scope -> reinstall with scopes, ratelimited -> back off).","Reconnect the Slack connection to refresh the bot token if invalid_auth.","Reinstall the Slack app requesting channels:read and groups:read bot scopes if missing_scope.","Add exponential backoff / reduce request frequency if ratelimited.","Check Slack API status for incidents."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Validate token + scopes before calling conversations.list:\nconst auth = await fetch('https://slack.com/api/auth.test', {\n  method: 'POST', headers: { Authorization: `Bearer ${botToken}` },\n}).then(r => r.json());\nif (!auth.ok) throw new Error(`Slack token invalid: ${auth.error}`);","typeGuard":"function isSlackOkBody<T>(b: T & { ok?: boolean }): b is T & { ok: true } {\n  return (b as { ok?: boolean }).ok === true;\n}","tryCatchPattern":"try { const channels = await listSlackBotChannels(input); }\ncatch (e) {\n  const err = /Slack inventory failed: (\\S+)/.exec(e.message)?.[1];\n  if (err === 'ratelimited') await sleep(backoff);\n  else if (err === 'invalid_auth') await reconnectSlack();\n  else if (err === 'missing_scope') await reinstallSlackApp(['channels:read','groups:read']);\n}","preventionTips":["Request channels:read and groups:read bot scopes at install time.","Rotate/refresh bot tokens proactively and reconnect on invalid_auth.","Throttle conversations.list pagination to respect Slack rate-limit tiers.","Check Slack API status during outages."],"tags":["slack","api","inventory","error-code"],"backgroundTag":"upstream-api-error","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}