thedotmack/claude-mem · error

ValidationError

ValidationError

Error message

ValidationError

What it means

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.

Solutions

  1. Read the issues array in the 400 response; each entry names path and expected type
  2. Fix the client payload to match observationsSchema (required fields and types)
  3. Check the client SDK version matches the server's compat API version
  4. Add client-side schema validation with the same zod schema before sending

Example fix

// before
await fetch('/api/sessions/observations', { method: 'POST', body: JSON.stringify({ obs }) });
// after
await fetch('/api/sessions/observations', {
  method: 'POST',
  body: JSON.stringify({ observations: obs, timestamp: new Date().toISOString() }),
});
Defensive patterns

Strategy: validation

Validate before calling

import { observationsSchema } from './schemas';
const check = observationsSchema.safeParse(payload);
if (!check.success) throw new Error(JSON.stringify(check.error.issues));

Type guard

function isValidObservations(p: unknown): p is ObservationsPayload {
  return observationsSchema.safeParse(p).success;
}

Try / catch

const res = await fetch('/api/sessions/observations', opts);
if (res.status === 400) {
  const { issues } = await res.json();
  throw new Error(`ValidationError: ${JSON.stringify(issues)}`);
}

Prevention

When it happens

Trigger: Posting /api/sessions/observations with missing required fields, wrong types (e.g. teamId as number), extra/malformed fields, or an empty body.

Common situations: Client SDK version drift against the compat endpoint; hand-written HTTP calls omitting required fields; serialization bugs sending null where a string is required.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/c7c4ca6c473dd620. Report an issue: GitHub.

Appendix: source

Thrown at src/server/compat/SessionsObservationsAdapter.ts:67

  ingestEvents: IngestEventsService;
  authMode?: string;
  allowLocalDevBypass?: boolean;
}

export class SessionsObservationsAdapter implements RouteHandler {
  constructor(private readonly options: SessionsObservationsAdapterOptions) {}

  setupRoutes(app: Application): void {
    const writeAuth = requirePostgresServerAuth(this.options.pool, {
      authMode: this.options.authMode,
      allowLocalDevBypass: this.options.allowLocalDevBypass,
      requiredScopes: ['memories:write'],
    });

    app.post('/api/sessions/observations', writeAuth, this.asyncHandler(async (req, res) => {
      const parsed = observationsSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({ error: 'ValidationError', issues: parsed.error.issues });
        return;
      }
      const teamId = req.authContext?.teamId ?? null;
      const projectId = req.authContext?.projectId ?? null;
      if (!teamId) {
        res.status(403).json({ error: 'Forbidden', message: 'API key is not bound to a team' });
        return;
      }
      if (!projectId) {
        // Compat mode requires a project-scoped key — the legacy payload does
        // not carry a Server beta projectId, so without scope we cannot place
        // the row in a tenant-scoped table.
        res.status(400).json({
          error: 'BadRequest',
          message: 'Legacy /api/sessions/observations requires a project-scoped API key',
        });
        return;
      }

View on GitHub (pinned to d8bc9755e7)