thedotmack/claude-mem · error · AppError
INVALID_SEARCH_REQUEST
INVALID_SEARCH_REQUEST
Error message
Either query or filters required for search
What it means
searchObservations requires at least one of a text query or usable filters. When query is empty/absent and buildFilterClause produces no clause from the remaining options, SessionSearch throws this AppError with code INVALID_SEARCH_REQUEST and HTTP 400, because a SQL search with no constraints is not a valid request.
Solutions
- Provide a non-empty query string, e.g. searchObservations(db, 'login bug').
- If you want a filter-only search, pass at least one recognized filter (e.g. { project: 'myapp' } or a date range).
- Check filter key spelling and that values are non-empty — pagination options (limit/offset/orderBy) do not count as filters.
- If listing everything is intended, use a dedicated list/observations endpoint instead of search.
Example fix
// before
await search.searchObservations('', { limit: 10 });
// after
await search.searchObservations('', { limit: 10, project: 'myapp' }); Defensive patterns
Strategy: validation
Validate before calling
const hasFilters = Object.entries(rest).some(([k, v]) => !['limit','offset','orderBy'].includes(k) && v !== undefined && v !== null && v !== '');
if (!query && !hasFilters) throw new Error('Either query or filters required for search'); Try / catch
try {
results = await search.searchObservations(query, options);
} catch (err) {
if (err instanceof AppError && err.code === 'INVALID_SEARCH_REQUEST') {
return respond(400, 'Provide a search query or at least one filter.');
}
throw err;
} Prevention
- Require a non-empty query or at least one filter in the UI/API layer.
- Exclude pagination keys when checking whether filters exist.
- Use a dedicated list API for unfiltered browsing.
- Validate filter key names against the supported set.
When it happens
Trigger: searchObservations is called with query = ''/undefined and options whose filters (project, agent, date range, etc.) are all empty or unsupported, so buildFilterClause returns a falsy clause.
Common situations: A UI search box submitted blank with no active filters; API client sent only pagination options (limit/offset) which are destructured out of filters; filter keys were misspelled so none matched recognized filter fields.
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
- cloud sync canonical payload
- FTS5 not available — user_prompts_fts skipped (search uses…
- observation_search: "query" is required
- schema v46: . row is not a positive canonical uint64…
- storeObservation requires a non-empty title
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/7c97a9c1f844b3c8.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sqlite/SessionSearch.ts:287
case 'relevance':
return hasFTS ? `ORDER BY ${ftsTable}.rank ASC` : 'ORDER BY o.created_at_epoch DESC';
case 'date_desc':
return 'ORDER BY o.created_at_epoch DESC';
case 'date_asc':
return 'ORDER BY o.created_at_epoch ASC';
default:
return 'ORDER BY o.created_at_epoch DESC';
}
}
searchObservations(query: string | undefined, options: SearchOptions = {}): ObservationSearchResult[] {
const params: any[] = [];
const { limit = 50, offset = 0, orderBy = 'relevance', ...filters } = options;
if (!query) {
const filterClause = this.buildFilterClause(filters, params, 'o');
if (!filterClause) {
throw new AppError(SessionSearch.MISSING_SEARCH_INPUT_MESSAGE, 400, 'INVALID_SEARCH_REQUEST');
}
const orderClause = this.buildOrderClause(orderBy, false);
const sql = `
SELECT o.*, o.discovery_tokens
FROM observations o
WHERE ${filterClause}
${orderClause}
LIMIT ? OFFSET ?
`;
params.push(limit, offset);
return this.db.prepare(sql).all(...params) as ObservationSearchResult[];
}
if (SessionSearch.UNSEGMENTED_SCRIPT.test(query)) {
const filterClause = this.buildFilterClause(filters, params, 'o');View on GitHub (pinned to d8bc9755e7)