Budibase/budibase · error · HTTPError
Slack app configuration refresh token is invalid. Save a new
Error message
Slack app configuration refresh token is invalid. Save a new config token and refresh token.
What it means
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.
Source
Thrown at packages/server/src/sdk/workspace/ai/deployments/slack.ts:181
refresh_token?: string
exp?: number
}
const assertSlackOk = <T extends SlackApiResponse>(
payload: T,
action: string
) => {
if (payload.ok) {
return payload
}
if (payload.error === "token_expired") {
throw new HTTPError(
"Slack app configuration token has expired. Save a new config token and refresh token.",
400
)
}
if (payload.error === "invalid_refresh_token") {
throw new HTTPError(
"Slack app configuration refresh token is invalid. Save a new config token and refresh token.",
400
)
}
const details = payload.errors?.map(error => error.message).filter(Boolean)
const message = details?.length
? `${action}: ${details.join(", ")}`
: `${action}: ${payload.error || "unknown_error"}`
throw new HTTPError(message, 400)
}
export const createSlackAppFromManifest = async ({
configToken,
manifest,
}: {
configToken: string
manifest: ReturnType<typeof buildSlackManifest>
}) => {View on GitHub (pinned to a81a902e9a)
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.
Example fix
// before
await rotateSlackConfigToken({ refreshToken: oldUsedRefreshToken }) // invalid_refresh_token
// after
// redo Slack setup to get a new pair, then persist BOTH values
await saveAgentSlackIntegration({
configToken: newPair.configToken,
refreshToken: newPair.refreshToken // store the NEW refresh token
}) Defensive patterns
Strategy: try-catch
Try / catch
try {
return await rotateSlackConfigToken({ refreshToken })
} catch (e) {
if (e instanceof HTTPError && e.message.includes("refresh token is invalid")) {
// refresh tokens are single-use/revoked: re-run Slack app setup to get a new pair
throw new Error("Slack setup must be repeated: refresh token no longer valid")
}
throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Slack app creation response was incomplete
- Slack OAuth callback is missing state
- Slack OAuth state is invalid or expired
- Slack OAuth authorization failed
- Slack OAuth callback is missing the authorization code
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/6f9c10b0c53709c1.
Report an issue: GitHub.