{"record":{"id":"ab31a9cbce912c02","repo":"Budibase/budibase","slug":"preview-mode-is-required","errorCode":null,"errorMessage":"Preview mode is required","messagePattern":"Preview mode is required","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/api/controllers/ai/chatConversations.ts","lineNumber":387,"sourceCode":"\nconst resolveChatStreamRequest = async (\n  ctx: UserCtx<ChatAgentRequest, void>\n): Promise<ResolvedChatStreamRequest> => {\n  const chat = ctx.request.body\n  const userId = getGlobalUserId(ctx)\n  applyChatStreamPathParams(chat, ctx.params)\n\n  const workspaceId = context.getWorkspaceId()\n  if (!workspaceId) {\n    throw new HTTPError(\"Workspace context is required\", 400)\n  }\n  const isBuilderOrAdmin = usersSdk.users.isAdminOrBuilder(\n    ctx.user,\n    workspaceId\n  )\n\n  if (chat.isPreview !== true) {\n    throw new HTTPError(\"Preview mode is required\", 400)\n  }\n\n  if (!isBuilderOrAdmin) {\n    throw new HTTPError(\"Forbidden\", 403)\n  }\n\n  if (!isDevWorkspaceID(workspaceId)) {\n    throw new HTTPError(\"Preview mode requires a development workspace\", 400)\n  }\n\n  let user = ctx.user\n  if (chat.previewRoleId) {\n    const previewRole = await roles.getRole(chat.previewRoleId)\n    if (!previewRole?._id) {\n      throw new HTTPError(\"Preview role not found\", 400)\n    }\n    user = {\n      ...ctx.user,","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/ai/chatConversations.ts#L369-L405","documentation":"The chat stream endpoint only supports preview mode: body.isPreview must be exactly true. Non-preview (published-app runtime) chat streaming is not allowed through this route, so any other value throws HTTP 400 'Preview mode is required'.","triggerScenarios":"POST to the chat stream endpoint with body.isPreview false, undefined, or a truthy-but-not-true value like \"true\" (string) or 1.","commonSituations":"Integrations built before the preview-only restriction; clients serializing booleans as strings; attempting to run agent chat in a published app via this endpoint.","solutions":["Set isPreview: true (boolean) in the request body","If you need chat in a published app, use the appropriate production chat route instead of this preview stream endpoint","Fix client serialization so isPreview is a real boolean"],"exampleFix":"// before\n{ \"agentId\": \"agent_1\", \"isPreview\": \"true\" }\n// after\n{ \"agentId\": \"agent_1\", \"isPreview\": true }","handlingStrategy":"validation","validationCode":"if (body.isPreview !== true) {\n  throw new Error(\"Chat stream requires isPreview: true (boolean)\")\n}","typeGuard":"const isPreviewRequest = (b: { isPreview?: unknown }): b is { isPreview: true } =>\n  b.isPreview === true","tryCatchPattern":"try {\n  await streamChat({ ...body, isPreview: true })\n} catch (e) {\n  if (e.status === 400 && String(e.message).includes(\"Preview mode is required\")) {\n    // fix the isPreview flag before retrying\n  }\n}","preventionTips":["Always send isPreview: true as a real boolean","Beware JSON serializers turning booleans into strings","Use the production chat route for non-preview scenarios"],"tags":["validation","http-400","preview-mode"],"backgroundTag":"missing-required-flag","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}