{"record":{"id":"6f9c10b0c53709c1","repo":"Budibase/budibase","slug":"slack-app-configuration-refresh-token-is-invalid","errorCode":null,"errorMessage":"Slack app configuration refresh token is invalid. Save a new config token and refresh token.","messagePattern":"Slack app configuration refresh token is invalid\\. Save a new config token and refresh token\\.","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/ai/deployments/slack.ts","lineNumber":181,"sourceCode":"  refresh_token?: string\n  exp?: number\n}\n\nconst assertSlackOk = <T extends SlackApiResponse>(\n  payload: T,\n  action: string\n) => {\n  if (payload.ok) {\n    return payload\n  }\n  if (payload.error === \"token_expired\") {\n    throw new HTTPError(\n      \"Slack app configuration token has expired. Save a new config token and refresh token.\",\n      400\n    )\n  }\n  if (payload.error === \"invalid_refresh_token\") {\n    throw new HTTPError(\n      \"Slack app configuration refresh token is invalid. Save a new config token and refresh token.\",\n      400\n    )\n  }\n  const details = payload.errors?.map(error => error.message).filter(Boolean)\n  const message = details?.length\n    ? `${action}: ${details.join(\", \")}`\n    : `${action}: ${payload.error || \"unknown_error\"}`\n  throw new HTTPError(message, 400)\n}\n\nexport const createSlackAppFromManifest = async ({\n  configToken,\n  manifest,\n}: {\n  configToken: string\n  manifest: ReturnType<typeof buildSlackManifest>\n}) => {","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/deployments/slack.ts#L163-L199","documentation":"This HTTP 400 error is thrown by assertSlackOk when Slack responds with error 'invalid_refresh_token' during token rotation or an operation using the config token flow. It means the stored Slack configuration refresh token is no longer accepted by Slack - it was revoked, already used, or never valid. The user must redo the config token setup.","triggerScenarios":"Calling rotateSlackConfigToken (or any path through assertSlackOk that exercises the refresh flow) with a refresh token Slack rejects - e.g. the token was already consumed in a previous rotation, the Slack app was deleted, or the token string was truncated/mis-copied.","commonSituations":"Slack refresh tokens are single-use: storing the old refresh token after a successful rotation makes the next rotation fail; the Slack app was uninstalled/deleted; token was copied without the trailing characters.","solutions":["Repeat the Slack app configuration setup to obtain a brand-new config token + refresh token pair and save both in the agent settings.","Ensure every successful rotation result is persisted - overwrite the stored refresh token with the new one returned each time.","Verify the Slack app still exists in your workspace; recreate it if it was deleted, then redo setup.","Check the refresh token was copied in full (no truncation) from the Slack setup output."],"exampleFix":"// before\nawait rotateSlackConfigToken({ refreshToken: oldUsedRefreshToken }) // invalid_refresh_token\n// after\n// redo Slack setup to get a new pair, then persist BOTH values\nawait saveAgentSlackIntegration({\n  configToken: newPair.configToken,\n  refreshToken: newPair.refreshToken // store the NEW refresh token\n})","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await rotateSlackConfigToken({ refreshToken })\n} catch (e) {\n  if (e instanceof HTTPError && e.message.includes(\"refresh token is invalid\")) {\n    // refresh tokens are single-use/revoked: re-run Slack app setup to get a new pair\n    throw new Error(\"Slack setup must be repeated: refresh token no longer valid\")\n  }\n  throw e\n}","preventionTips":["Treat refresh tokens as single-use: overwrite the stored token immediately after each successful rotation.","Never rotate from two processes concurrently with the same refresh token.","Alert users to redo Slack setup rather than retrying endlessly once the refresh token is rejected."],"tags":["slack","oauth","refresh-token","invalid-credentials"],"backgroundTag":"invalid-refresh-token","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}