{"record":{"id":"42da8cef2cc2575e","repo":"Budibase/budibase","slug":"slack-app-configuration-token-has-expired-save-a","errorCode":null,"errorMessage":"Slack app configuration token has expired. Save a new config token and refresh token.","messagePattern":"Slack app configuration token has expired\\. 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":175,"sourceCode":"    name?: string\n  }\n}\n\ninterface SlackConfigTokenRotateResponse extends SlackApiResponse {\n  token?: string\n  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 ({","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/deployments/slack.ts#L157-L193","documentation":"This HTTP 400 error is thrown by assertSlackOk when a Slack API response returns ok:false with error 'token_expired'. Budibase uses Slack app configuration tokens (app config tokens with refresh tokens) for manifest-based app creation; these tokens expire and must be rotated. The message instructs you to save a new config token and refresh token pair.","triggerScenarios":"Calling createSlackAppFromManifest, exchangeSlackOAuthCode, or rotated() with a Slack configuration access token that Slack has expired - e.g. deploying/creating a Slack app with a config token captured hours/days earlier that has since expired.","commonSituations":"Config token stored in the agent/environment long ago and never refreshed; token rotation failed silently in a previous run; a stale token was copied from old documentation or a teammate's expired setup.","solutions":["Obtain a fresh Slack app configuration token and refresh token from the Slack app setup flow, then save both via the agent's Slack integration settings.","Call rotateSlackConfigToken with a valid refresh token to mint a new access token before retrying the operation.","Re-run the Slack OAuth/app-manifest setup from the Budibase UI to regenerate tokens end-to-end.","If refresh also fails with invalid_refresh_token, restart the full Slack app setup (see error 495)."],"exampleFix":"// before\nawait createSlackAppFromManifest({ configToken: staleToken, manifest }) // token_expired\n// after\nconst rotated = await rotateSlackConfigToken({ refreshToken: storedRefreshToken })\nawait createSlackAppFromManifest({ configToken: rotated.configToken, manifest })","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await createSlackAppFromManifest({ configToken, manifest })\n} catch (e) {\n  if (e instanceof HTTPError && e.message.includes(\"token has expired\")) {\n    const rotated = await rotateSlackConfigToken({ refreshToken })\n    await createSlackAppFromManifest({ configToken: rotated.configToken, manifest })\n  } else throw e\n}","preventionTips":["Rotate the Slack config token proactively (tokens are short-lived) before long-running deploy operations.","Always persist the new config + refresh token pair returned by each rotation.","Timestamp stored tokens and prompt for re-setup when they age past the known lifetime."],"tags":["slack","token-expired","oauth"],"backgroundTag":"token-expired","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}