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
- 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
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
- 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
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)