{"record":{"id":"a13fcc1ae6c07e71","repo":"Budibase/budibase","slug":"action-details-join-action-pa","errorCode":null,"errorMessage":"${action}: ${details.join(\", \")} | ${action}: ${payload.error || \"unknown_error\"}","messagePattern":"(.+?): (.+?) \\| (.+?): (.+?)","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/ai/deployments/slack.ts","lineNumber":190,"sourceCode":"    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 ({\n  configToken,\n  manifest,\n}: {\n  configToken: string\n  manifest: ReturnType<typeof buildSlackManifest>\n}) => {\n  const response = await fetch(`${SLACK_API_BASE}/apps.manifest.create`, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      Authorization: `Bearer ${configToken}`,\n    },\n    body: JSON.stringify({\n      manifest: JSON.stringify(manifest),\n    }),","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/deployments/slack.ts#L172-L208","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the error message text - it contains the Slack error code or detailed messages after the action prefix; fix the specific issue it names.","If the OAuth code is the problem, restart the OAuth flow to get a fresh code (codes are single-use and short-lived).","If the manifest is rejected, validate the Slack app manifest against Slack's schema and correct the reported field.","Verify client_id/client_secret match the Slack app credentials exactly.","For rate limits, wait and retry the Slack operation after a delay."],"exampleFix":"// before - no visibility into which Slack call failed\nassertSlackOk(payload, \"Failed to create Slack app\")\n// after - inspect message prefix to identify the failing action and Slack error\ntry {\n  await createSlackAppFromManifest({ configToken, manifest })\n} catch (e) {\n  // e.message e.g. 'Failed to create Slack app: invalid_manifest'\n  // adjust manifest / credentials per the Slack error code\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await createSlackAppFromManifest({ configToken, manifest })\n} catch (e) {\n  if (e instanceof HTTPError) {\n    // message is '<action>: <slack error code | detail messages>'\n    const slackError = e.message.split(\": \")[1]\n    // branch on slackError e.g. 'invalid_manifest', 'code_already_used'\n  }\n  throw e\n}","preventionTips":["Validate Slack app manifests against Slack's schema before submission.","Use each OAuth authorization code exactly once and promptly.","Log the full error message (it embeds Slack's error code and detail messages) for diagnosis.","Add backoff for rate-limit style Slack errors."],"tags":["slack","api-error","manifest","oauth"],"backgroundTag":"upstream-api-error","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}