{"record":{"id":"c381cfaf8c8f79bb","repo":"Budibase/budibase","slug":"agentid-is-required-c381cf","errorCode":null,"errorMessage":"agentId is required","messagePattern":"agentId is required","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/ai/chatConversations/helpers.ts","lineNumber":36,"sourceCode":"}\n\nexport const prepareChatConversationForSave = ({\n  chatId,\n  userId,\n  title,\n  messages,\n  chat,\n  existingChat,\n}: PrepareChatConversationForSaveParams): ChatConversation => {\n  const now = new Date().toISOString()\n  const createdAt = existingChat?.createdAt || chat.createdAt || now\n  const updatedAt = now\n  const rev = existingChat?._rev || chat._rev\n  const agentId = existingChat?.agentId || chat.agentId\n  const channel = chat.channel || existingChat?.channel\n\n  if (!agentId) {\n    throw new HTTPError(\"agentId is required\", 400)\n  }\n\n  return {\n    _id: chatId,\n    ...(rev && { _rev: rev }),\n    agentId,\n    userId,\n    title: title ?? chat.title,\n    messages: truncateToolPartsForSave(messages),\n    updatedAt,\n    ...(createdAt && { createdAt }),\n    ...(channel && { channel }),\n  }\n}\n\nexport const extractUserText = (\n  message?: ChatConversation[\"messages\"][number]\n) => {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/chatConversations/helpers.ts#L18-L54","documentation":"prepareChatConversationForSave builds the ChatConversation document to persist. It resolves agentId from the existing chat or the incoming request; if neither provides one, the conversation cannot be associated with an agent and a 400 HTTPError is thrown. The field is required for every saved chat conversation.","triggerScenarios":"Saving/creating a chat conversation where chat.agentId is missing and there is no existingChat to inherit it from - e.g. a client POSTing a conversation payload without agentId, or updating a conversation whose stored agentId was lost.","commonSituations":"Custom chat integrations omitting agentId in the request body; API version changes altering required fields; corrupted/existing conversations missing agentId being updated.","solutions":["Include agentId in the ChatConversationRequest payload when creating/updating conversations.","Verify the existing conversation document has agentId before attempting updates.","Catch the 400 HTTPError and reject/repair requests missing agentId at the API boundary."],"exampleFix":"// before\nawait api.saveChatConversation({ chatId, messages }) // 400: agentId required\n// after\nawait api.saveChatConversation({ chatId, agentId: agent._id, messages })","handlingStrategy":"validation","validationCode":"const canSave = (chat: Partial<ChatConversationRequest>, existing?: ChatConversation | null) =>\n  !!(existing?.agentId || chat.agentId)\nif (!canSave(chat, existingChat)) {\n  throw new HTTPError(\"agentId is required\", 400)\n}","typeGuard":"const hasAgentId = (\n  chat: Partial<ChatConversationRequest>,\n  existingChat?: ChatConversation | null\n): chat is Partial<ChatConversationRequest> & { agentId: string } =>\n  !!(existingChat?.agentId || chat.agentId)","tryCatchPattern":"try {\n  const doc = prepareChatConversationForSave(params)\n} catch (err) {\n  if (err instanceof HTTPError && err.status === 400 && err.message === \"agentId is required\") {\n    // reject the request / repair the payload with the resolved agentId\n  }\n}","preventionTips":["Validate agentId presence in request-body schemas at the API layer.","Always pass agentId explicitly when creating conversations; never rely on inheritance.","Include agentId in chat client SDK request types as required."],"tags":["validation","http-400","chat"],"backgroundTag":"missing-required-field","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}