thedotmack/claude-mem · warning
message
Error message
message
What it means
badRequest is BaseRouteHandler's helper that responds 400 with `{ error: message }`. The thrown 'message' here is the helper's parameter — the concrete text comes from callers like parseIntParam when a required numeric/typed query param fails to parse.
Solutions
- Send a valid integer for the parameter (e.g. ?limit=50)
- Inspect the route's parseIntParam call to see the expected param name and constraints
- Omit optional params entirely instead of sending empty values
Example fix
// before GET /api/observations?limit=abc // after GET /api/observations?limit=50
Defensive patterns
Strategy: validation
Validate before calling
function isValidIntParam(v: unknown): v is number {
const n = Number(v);
return Number.isInteger(n) && n > 0;
}
// before sending: if (!isValidIntParam(limit)) omit param; Type guard
function isPositiveInt(v: unknown): v is number {
return typeof v === 'number' && Number.isInteger(v) && v > 0;
} Prevention
- Validate all query params client-side before requests
- Never send empty strings for optional numeric params
- Use a typed client wrapper that enforces int params
When it happens
Trigger: Calling a worker API route with a query parameter that parseIntParam cannot parse (non-numeric where an int is required, empty value).
Common situations: Passing 'abc' or '' as ?limit= or ?id=; URL-encoded garbage in pagination params; SDK/client sending string types where ints are expected.
Understand the failure class
Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.
Related errors
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/caa9a2e2e8bcbfef.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/worker/http/BaseRouteHandler.ts:77
?? req.get?.('x-claude-mem-platform-source');
return BaseRouteHandler.firstString(req.query.platformSource)
?? BaseRouteHandler.firstString(req.query.platform_source)
?? BaseRouteHandler.firstString(body.platformSource)
?? BaseRouteHandler.firstString(body.platform_source)
?? BaseRouteHandler.firstString(header);
}
protected getPlatformSourceFromRequest(req: Request): string {
return normalizePlatformSource(BaseRouteHandler.rawPlatformSourceFromRequest(req));
}
protected getOptionalPlatformSourceFromRequest(req: Request): string | undefined {
const rawPlatformSource = BaseRouteHandler.rawPlatformSourceFromRequest(req);
return rawPlatformSource ? normalizePlatformSource(rawPlatformSource) : undefined;
}
protected badRequest(res: Response, message: string): void {
res.status(400).json({ error: message });
}
protected notFound(res: Response, message: string): void {
res.status(404).json({ error: message });
}
protected handleError(res: Response, error: Error, context?: string): void {
const statusCode = error instanceof AppError ? error.statusCode : 500;
// Client errors (4xx AppErrors) are routine bad input, not server faults, so
// they log at WARN and are NOT routed to the error sink — surfacing a
// validation rejection like a bad corpus name as a captured $exception just
// pollutes error tracking with noise. Only true server faults (5xx, or any
// non-AppError, which maps to 500) go through logger.failure, whose Error
// payload routes through logger.error → the error sink → captureException
// (Phase 3): a REDACTED $exception to PostHog Error Tracking, consent-gated,
// kill-switch-gated, and rate-limited.
const isClientError = statusCode >= 400 && statusCode < 500;
if (isClientError) {View on GitHub (pinned to d8bc9755e7)