{"record":{"id":"eb0707611f2c4f06","repo":"mastra-ai/mastra","slug":"messages-are-required","errorCode":null,"errorMessage":"Messages are required","messagePattern":"Messages are required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"packages/server/src/server/handlers/memory.ts","lineNumber":1301,"sourceCode":"  responseType: 'json',\n  queryParamSchema: agentIdQuerySchema,\n  bodySchema: saveMessagesBodySchema,\n  responseSchema: saveMessagesResponseSchema,\n  summary: 'Save messages',\n  description: 'Saves new messages to memory',\n  tags: ['Memory'],\n  requiresAuth: true,\n  handler: async ({ mastra, agentId, messages, requestContext }) => {\n    try {\n      const effectiveResourceId = getEffectiveResourceId(requestContext, undefined);\n      const memory = await getMemoryFromContext({ mastra, agentId, requestContext });\n\n      if (!memory) {\n        throw new HTTPException(400, { message: 'Memory is not initialized' });\n      }\n\n      if (!messages) {\n        throw new HTTPException(400, { message: 'Messages are required' });\n      }\n\n      if (!Array.isArray(messages)) {\n        throw new HTTPException(400, { message: 'Messages should be an array' });\n      }\n\n      // The body schema is intentionally permissive (unknown[]); narrow to the\n      // fields this handler validates and normalizes.\n      const incomingMessages = messages as Array<\n        { id?: string; threadId?: string; resourceId?: string; createdAt?: string | Date } & Record<string, unknown>\n      >;\n\n      const resourceIdByThread = new Map<string, string>();\n      for (const message of incomingMessages) {\n        if (!message.threadId || !message.resourceId) {\n          continue;\n        }\n        const existingResourceId = resourceIdByThread.get(message.threadId);","sourceCodeStart":1283,"sourceCodeEnd":1319,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/memory.ts#L1283-L1319","documentation":"After memory is resolved, the save-messages handler checks that a messages payload was supplied. A falsy messages value throws HTTPException(400, 'Messages are required').","triggerScenarios":"POST to the save-messages endpoint with an omitted or undefined messages field in the body.","commonSituations":"Client sends an empty body or only threadId/resourceId; a build/serialization step drops the messages key; fetch called without JSON body.","solutions":["Always include a messages array in the request body (may be empty []).","Validate the payload client-side before the call.","Check Content-Type is application/json and the body is actually stringified.","If no messages should be saved, don't call the endpoint at all."],"exampleFix":"// before\nawait fetch(url, { method: 'POST' }); // no body\n// after\nawait fetch(url, {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ threadId, messages }),\n});","handlingStrategy":"validation","validationCode":"if (!Array.isArray(messages)) {\n  throw new TypeError('messages must be an array before calling saveMessages');\n}","typeGuard":"function isMessageArray(v: unknown): v is Message[] {\n  return Array.isArray(v) && v.every(m => !!m && typeof m === 'object' && typeof (m as any).role === 'string');\n}","tryCatchPattern":"try {\n  await saveMessages({ threadId, messages });\n} catch (e) {\n  if (isHttpException(e, 400) && /messages are required/i.test(e.message)) {\n    logger.warn('saveMessages called without a payload; check request construction');\n    return;\n  }\n  throw e;\n}","preventionTips":["Build request bodies with a typed client that requires the messages field.","Always stringify JSON bodies and set Content-Type: application/json.","Skip the API call entirely when there is nothing to persist."],"tags":["http-400","validation","request-body"],"backgroundTag":"missing-required-parameter","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}