thedotmack/claude-mem · error
ValidationError
ValidationError
Error message
ValidationError
What it means
The legacy /api/sessions/summarize compat route validates req.body against summarizeSchema with safeParse and returns HTTP 400 { error:'ValidationError', issues:[...] } when the payload does not match. This is the adapter's input-contract enforcement before any ingestion happens.
Solutions
- Read the issues array in the 400 response — it lists exact failing paths and expected types
- Align the client payload with summarizeSchema (required fields and types)
- If the schema changed, update the legacy client or relax/extend the schema in the adapter
- Test the payload with a quick safeParse in a script before calling the endpoint
Example fix
// before
await fetch('/api/sessions/summarize', { method: 'POST', body: JSON.stringify({}) });
// after
await fetch('/api/sessions/summarize', { method: 'POST', body: JSON.stringify({ contentSessionId: 'sess_123' }) }); Defensive patterns
Strategy: validation
Validate before calling
// mirror summarizeSchema on the client before POSTing
import { summarizeSchema } from './schemas';
const parsed = summarizeSchema.safeParse(body);
if (!parsed.success) throw new Error(`Invalid summarize payload: ${JSON.stringify(parsed.error.issues)}`); Type guard
const isValidSummarizeBody = (b) => typeof b?.contentSessionId === 'string' && b.contentSessionId.length > 0;
Try / catch
// handle 400 validation errors explicitly
if (res.status === 400 && body.error === 'ValidationError') {
console.error('Payload rejected:', body.issues);
} Prevention
- Generate the client payload types from the shared zod schema
- Validate payloads in CI with the same schema the server uses
- Pin client versions against server schema changes and read the issues array on failure
When it happens
Trigger: POST /api/sessions/summarize with a body missing required fields (e.g. contentSessionId) or with wrong types, per summarizeSchema in SessionsSummarizeAdapter.ts.
Common situations: Older Claude Code clients sending a payload shape that drifted from the current summarizeSchema; manual curl testing with incomplete JSON; client bug after a schema field was renamed or made 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/42a384393683c809.
Report an issue: GitHub.
Appendix: source
Thrown at src/server/compat/SessionsSummarizeAdapter.ts:53
endSession: EndSessionService;
authMode?: string;
allowLocalDevBypass?: boolean;
}
export class SessionsSummarizeAdapter implements RouteHandler {
constructor(private readonly options: SessionsSummarizeAdapterOptions) {}
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/summarize', writeAuth, this.asyncHandler(async (req, res) => {
const parsed = summarizeSchema.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) {
res.status(400).json({
error: 'BadRequest',
message: 'Legacy /api/sessions/summarize requires a project-scoped API key',
});
return;
}
// Subagent contexts in legacy code emit summarize calls but the worker
// skipped them. We preserve the legacy semantics so existing clientsView on GitHub (pinned to d8bc9755e7)