{"record":{"id":"7c97a9c1f844b3c8","repo":"thedotmack/claude-mem","slug":"invalid-search-request","errorCode":"INVALID_SEARCH_REQUEST","errorMessage":"Either query or filters required for search","messagePattern":"Either query or filters required for search","errorType":"error_code","errorClass":"AppError","httpStatus":400,"severity":"error","filePath":"src/services/sqlite/SessionSearch.ts","lineNumber":287,"sourceCode":"      case 'relevance':\n        return hasFTS ? `ORDER BY ${ftsTable}.rank ASC` : 'ORDER BY o.created_at_epoch DESC';\n      case 'date_desc':\n        return 'ORDER BY o.created_at_epoch DESC';\n      case 'date_asc':\n        return 'ORDER BY o.created_at_epoch ASC';\n      default:\n        return 'ORDER BY o.created_at_epoch DESC';\n    }\n  }\n\n  searchObservations(query: string | undefined, options: SearchOptions = {}): ObservationSearchResult[] {\n    const params: any[] = [];\n    const { limit = 50, offset = 0, orderBy = 'relevance', ...filters } = options;\n\n    if (!query) {\n      const filterClause = this.buildFilterClause(filters, params, 'o');\n      if (!filterClause) {\n        throw new AppError(SessionSearch.MISSING_SEARCH_INPUT_MESSAGE, 400, 'INVALID_SEARCH_REQUEST');\n      }\n\n      const orderClause = this.buildOrderClause(orderBy, false);\n\n      const sql = `\n        SELECT o.*, o.discovery_tokens\n        FROM observations o\n        WHERE ${filterClause}\n        ${orderClause}\n        LIMIT ? OFFSET ?\n      `;\n\n      params.push(limit, offset);\n      return this.db.prepare(sql).all(...params) as ObservationSearchResult[];\n    }\n\n    if (SessionSearch.UNSEGMENTED_SCRIPT.test(query)) {\n      const filterClause = this.buildFilterClause(filters, params, 'o');","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/sqlite/SessionSearch.ts#L269-L305","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait search.searchObservations('', { limit: 10 });\n// after\nawait search.searchObservations('', { limit: 10, project: 'myapp' });","handlingStrategy":"validation","validationCode":"const hasFilters = Object.entries(rest).some(([k, v]) => !['limit','offset','orderBy'].includes(k) && v !== undefined && v !== null && v !== '');\nif (!query && !hasFilters) throw new Error('Either query or filters required for search');","typeGuard":null,"tryCatchPattern":"try {\n  results = await search.searchObservations(query, options);\n} catch (err) {\n  if (err instanceof AppError && err.code === 'INVALID_SEARCH_REQUEST') {\n    return respond(400, 'Provide a search query or at least one filter.');\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["search","validation","sqlite","api"],"backgroundTag":"invalid-query-parameter","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}