{"record":{"id":"c0d076d83fd658bb","repo":"CherryHQ/cherry-studio","slug":"slack-bot-token-xoxb-is-required","errorCode":null,"errorMessage":"Slack bot token (xoxb-...) is required","messagePattern":"Slack bot token \\(xoxb-\\.\\.\\.\\) is required","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/channels/adapters/slack/SlackAdapter.ts","lineNumber":227,"sourceCode":"  private readonly streamingControllers = new Map<string, SlackStreamingController>()\n  /** Track the latest incoming message ts per chatId for reaction acknowledgment */\n  private readonly pendingReactions = new Map<string, string>()\n\n  constructor(config: ChannelAdapterConfig<'slack'>) {\n    super(config)\n    const { bot_token, app_token, allowed_channel_ids } = config.channelConfig\n    this.botToken = bot_token\n    this.appToken = app_token\n    this.allowedChannelIds = allowed_channel_ids ?? []\n    this.notifyChatIds = [...this.allowedChannelIds]\n  }\n\n  protected override async checkReady(): Promise<boolean> {\n    return !!(this.botToken && this.appToken)\n  }\n\n  protected override async performConnect(_signal: AbortSignal): Promise<void> {\n    if (!this.botToken) throw new Error('Slack bot token (xoxb-...) is required')\n    if (!this.appToken) throw new Error('Slack app-level token (xapp-...) is required for Socket Mode')\n    this.shouldStop = false\n    await this.fetchBotUserId()\n    await this.startSocketMode()\n    this.log.info('Slack bot started')\n  }\n\n  protected override async performDisconnect(): Promise<void> {\n    this.shouldStop = true\n    for (const controller of this.streamingControllers.values()) {\n      controller.dispose()\n    }\n    this.streamingControllers.clear()\n    this.pendingReactions.clear()\n    this.cleanup()\n    this.log.info('Slack bot stopped')\n  }\n","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/channels/adapters/slack/SlackAdapter.ts#L209-L245","documentation":"Thrown by SlackAdapter.performConnect() when bot_token is missing. Slack requires a bot token (xoxb-) to call Web API methods like auth.test (fetchBotUserId) and to identify the bot. The guard fails fast before any Slack call.","triggerScenarios":"Channel config's channelConfig.bot_token is empty/undefined; performConnect throws immediately, before fetchBotUserId() and startSocketMode().","commonSituations":"User added a Slack channel but only supplied the app-level token (xapp-), or copied the wrong token type, or the config value didn't persist.","solutions":["From the Slack App's OAuth & Permissions page, install the app to the workspace and copy the Bot User OAuth Token (starts with xoxb-).","Paste it into channelConfig.bot_token and re-attempt connect.","Ensure the token starts with 'xoxb-' (a different prefix like xapp- belongs in app_token).","Rely on checkReady() (requires both botToken and appToken) to keep the adapter 'not ready' until configured."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate tokens before allowing connect.\nfunction slackTokensPresent(cfg: SlackChannelConfig): boolean {\n  return Boolean(cfg.bot_token?.startsWith('xoxb-') && cfg.app_token?.startsWith('xapp-'))\n}","typeGuard":"function isSlackMissingBotToken(e: unknown): e is Error {\n  return e instanceof Error && e.message === 'Slack bot token (xoxb-...) is required'\n}","tryCatchPattern":"if (!slackTokensPresent(cfg)) { showConfigError('Provide Slack xoxb- and xapp- tokens'); return }\ntry { await slack.connect() } catch (e) {\n  if (isSlackMissingBotToken(e)) { showConfigError('Provide the Slack bot token (xoxb-)'); return }\n  throw e\n}","preventionTips":["Install the app to the workspace and copy the Bot User OAuth Token (xoxb-) from OAuth & Permissions.","Use the app-level token (xapp-) only in app_token; never swap the two.","Keep the adapter 'not ready' (checkReady requires both) until configured."],"tags":["slack","credentials","config","validation","lifecycle"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}