{"record":{"id":"c7c4ca6c473dd620","repo":"thedotmack/claude-mem","slug":"validationerror","errorCode":"ValidationError","errorMessage":"ValidationError","messagePattern":"ValidationError","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"src/server/compat/SessionsObservationsAdapter.ts","lineNumber":67,"sourceCode":"  ingestEvents: IngestEventsService;\n  authMode?: string;\n  allowLocalDevBypass?: boolean;\n}\n\nexport class SessionsObservationsAdapter implements RouteHandler {\n  constructor(private readonly options: SessionsObservationsAdapterOptions) {}\n\n  setupRoutes(app: Application): void {\n    const writeAuth = requirePostgresServerAuth(this.options.pool, {\n      authMode: this.options.authMode,\n      allowLocalDevBypass: this.options.allowLocalDevBypass,\n      requiredScopes: ['memories:write'],\n    });\n\n    app.post('/api/sessions/observations', writeAuth, this.asyncHandler(async (req, res) => {\n      const parsed = observationsSchema.safeParse(req.body);\n      if (!parsed.success) {\n        res.status(400).json({ error: 'ValidationError', issues: parsed.error.issues });\n        return;\n      }\n      const teamId = req.authContext?.teamId ?? null;\n      const projectId = req.authContext?.projectId ?? null;\n      if (!teamId) {\n        res.status(403).json({ error: 'Forbidden', message: 'API key is not bound to a team' });\n        return;\n      }\n      if (!projectId) {\n        // Compat mode requires a project-scoped key — the legacy payload does\n        // not carry a Server beta projectId, so without scope we cannot place\n        // the row in a tenant-scoped table.\n        res.status(400).json({\n          error: 'BadRequest',\n          message: 'Legacy /api/sessions/observations requires a project-scoped API key',\n        });\n        return;\n      }","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/server/compat/SessionsObservationsAdapter.ts#L49-L85","documentation":"POST /api/sessions/observations validates req.body with observationsSchema via zod safeParse. On failure the adapter responds 400 with error 'ValidationError' and the zod issues array. The client sent a payload that does not match the legacy observations schema.","triggerScenarios":"Posting /api/sessions/observations with missing required fields, wrong types (e.g. teamId as number), extra/malformed fields, or an empty body.","commonSituations":"Client SDK version drift against the compat endpoint; hand-written HTTP calls omitting required fields; serialization bugs sending null where a string is required.","solutions":["Read the issues array in the 400 response; each entry names path and expected type","Fix the client payload to match observationsSchema (required fields and types)","Check the client SDK version matches the server's compat API version","Add client-side schema validation with the same zod schema before sending"],"exampleFix":"// before\nawait fetch('/api/sessions/observations', { method: 'POST', body: JSON.stringify({ obs }) });\n// after\nawait fetch('/api/sessions/observations', {\n  method: 'POST',\n  body: JSON.stringify({ observations: obs, timestamp: new Date().toISOString() }),\n});","handlingStrategy":"validation","validationCode":"import { observationsSchema } from './schemas';\nconst check = observationsSchema.safeParse(payload);\nif (!check.success) throw new Error(JSON.stringify(check.error.issues));","typeGuard":"function isValidObservations(p: unknown): p is ObservationsPayload {\n  return observationsSchema.safeParse(p).success;\n}","tryCatchPattern":"const res = await fetch('/api/sessions/observations', opts);\nif (res.status === 400) {\n  const { issues } = await res.json();\n  throw new Error(`ValidationError: ${JSON.stringify(issues)}`);\n}","preventionTips":["Validate payloads client-side with the same zod schema","Keep client SDK and server compat API versions aligned","Log request bodies on 400 responses","Cover the endpoint with contract tests"],"tags":["http","validation","zod","api"],"backgroundTag":"schema-validation-failed","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}