Budibase/budibase · error · HTTPError

${action}: ${details.join(", ")} | ${action}: ${payload.erro

Error message

${action}: ${details.join(", ")} | ${action}: ${payload.error || "unknown_error"}

What it means

This HTTP 400 error is the generic failure thrown by assertSlackOk when a Slack API response is not ok and does not match the specific token_expired / invalid_refresh_token cases. The message is either '<action>: <joined error detail messages>' (when Slack returns a structured errors array) or '<action>: <payload.error or unknown_error>'. The action label identifies which Slack call failed.

Source

Thrown at packages/server/src/sdk/workspace/ai/deployments/slack.ts:190

    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>
}) => {
  const response = await fetch(`${SLACK_API_BASE}/apps.manifest.create`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${configToken}`,
    },
    body: JSON.stringify({
      manifest: JSON.stringify(manifest),
    }),

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Read the error message text - it contains the Slack error code or detailed messages after the action prefix; fix the specific issue it names.
  2. If the OAuth code is the problem, restart the OAuth flow to get a fresh code (codes are single-use and short-lived).
  3. If the manifest is rejected, validate the Slack app manifest against Slack's schema and correct the reported field.
  4. Verify client_id/client_secret match the Slack app credentials exactly.
  5. For rate limits, wait and retry the Slack operation after a delay.

Example fix

// before - no visibility into which Slack call failed
assertSlackOk(payload, "Failed to create Slack app")
// after - inspect message prefix to identify the failing action and Slack error
try {
  await createSlackAppFromManifest({ configToken, manifest })
} catch (e) {
  // e.message e.g. 'Failed to create Slack app: invalid_manifest'
  // adjust manifest / credentials per the Slack error code
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await createSlackAppFromManifest({ configToken, manifest })
} catch (e) {
  if (e instanceof HTTPError) {
    // message is '<action>: <slack error code | detail messages>'
    const slackError = e.message.split(": ")[1]
    // branch on slackError e.g. 'invalid_manifest', 'code_already_used'
  }
  throw e
}

Prevention

When it happens

Trigger: Any Slack API call routed through assertSlackOk - createSlackAppFromManifest, exchangeSlackOAuthCode, rotated - returning ok:false with an unrecognised error code (e.g. invalid_manifest, code_already_used, invalid_client, ratelimited) or a structured errors array.

Common situations: Malformed Slack app manifest; OAuth authorization code already redeemed or expired; wrong client_id/client_secret pair; Slack API rate limiting; Slack-side schema changes producing new error codes.

Related errors


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