Budibase/budibase · error · HTTPError
Failed to rotate Slack app configuration token
Error message
Failed to rotate Slack app configuration token
What it means
This error is thrown by rotateSlackConfigToken when the HTTP response from Slack's app configuration token rotation endpoint is non-ok. Token rotation exchanges a refresh token for a new config token + refresh token pair; an HTTP-level failure means the rotation request was rejected by Slack before producing a structured API payload.
Source
Thrown at packages/server/src/sdk/workspace/ai/deployments/slack.ts:263
}
export const rotateSlackConfigToken = async ({
refreshToken,
}: {
refreshToken: string
}) => {
const response = await fetch(`${SLACK_API_BASE}/tooling.tokens.rotate`, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
refresh_token: refreshToken,
}),
})
const payload = (await response.json()) as SlackConfigTokenRotateResponse
if (!response.ok) {
throw new HTTPError(
"Failed to rotate Slack app configuration token",
response.status
)
}
const rotated = assertSlackOk(
payload,
"Failed to rotate Slack app configuration token"
)
if (!rotated.token || !rotated.refresh_token || !rotated.exp) {
throw new HTTPError(
"Slack app configuration token rotation response was incomplete",
400
)
}
return {
configToken: rotated.token,View on GitHub (pinned to a81a902e9a)
Solutions
- Confirm a non-empty refresh token is being passed - inspect the stored value before calling rotateSlackConfigToken.
- Pass the refresh token (not the config/access token) to the rotation endpoint.
- If the Slack app was deleted, redo the Slack app setup to get a new config/refresh token pair.
- For 5xx statuses, retry the rotation after a short delay.
Example fix
// before
await rotateSlackConfigToken({ refreshToken: undefined }) // HTTP 400
// after
if (!stored.refreshToken) throw new Error("Refresh Slack config token via setup first")
const rotated = await rotateSlackConfigToken({ refreshToken: stored.refreshToken })
await persist({ configToken: rotated.configToken, refreshToken: rotated.refreshToken }) Defensive patterns
Strategy: try-catch
Validate before calling
if (!refreshToken?.trim()) {
throw new Error("Cannot rotate Slack config token: refresh token missing; redo Slack setup")
} Try / catch
try {
const rotated = await rotateSlackConfigToken({ refreshToken })
await persist(rotated) // save both new configToken and refreshToken
return rotated
} catch (e) {
if (e instanceof HTTPError && e.status >= 500) {
await sleep(5000) // transient Slack issue, safe to retry
return rotateSlackConfigToken({ refreshToken })
}
if (e instanceof HTTPError && e.status === 400) {
throw new Error("Refresh token rejected; repeat the Slack app setup")
}
throw e
} Prevention
- Persist rotation results atomically (config token + refresh token together).
- Check refresh token presence before calling rotation; missing token means redo setup, not retry.
- Only retry rotation on 5xx; 4xx means the token itself is bad.
- Rotate well before the config token's expiry window closes.
When it happens
Trigger: POSTing refresh_token to Slack's config token rotate endpoint and receiving 4xx/5xx - e.g. 400/401 from a malformed or empty refresh_token field, wrong endpoint/auth, or 5xx from Slack.
Common situations: The stored refresh token was emptied by a partial save or env var absence (empty string posted); Slack app deleted so the token's parent no longer exists; transient Slack outage; calling rotation with an access token instead of a refresh token.
Related errors
- Failed to exchange Slack OAuth code
- Slack app creation response was incomplete
- Slack OAuth callback is missing state
- Slack OAuth state is invalid or expired
- Slack OAuth authorization failed
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/6ac3a466bff59ba2.
Report an issue: GitHub.