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

  1. Repeat the Slack app configuration setup to obtain a brand-new config token + refresh token pair and save both in the agent settings.
  2. Ensure every successful rotation result is persisted - overwrite the stored refresh token with the new one returned each time.
  3. Verify the Slack app still exists in your workspace; recreate it if it was deleted, then redo setup.
  4. 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

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

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/6f9c10b0c53709c1. Report an issue: GitHub.