{"record":{"id":"ffef85606ddd5ee9","repo":"tobi/qmd","slug":"search-requires-either-query-or-queries","errorCode":null,"errorMessage":"search() requires either 'query' or 'queries'","messagePattern":"search\\(\\) requires either 'query' or 'queries'","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/index.ts","lineNumber":400,"sourceCode":"  // Create a per-store LlamaCpp instance — lazy-loads models on first use,\n  // auto-unloads after 5 min inactivity to free VRAM.\n  const llm = new LlamaCpp({\n    embedModel: config?.models?.embed,\n    generateModel: config?.models?.generate,\n    rerankModel: config?.models?.rerank,\n    inactivityTimeoutMs: 5 * 60 * 1000,\n    disposeModelsOnInactivity: true,\n  });\n  internal.llm = llm;\n\n  const store: QMDStore = {\n    internal,\n    dbPath: internal.dbPath,\n\n    // Search\n    search: async (opts) => {\n      if (!opts.query && !opts.queries) {\n        throw new Error(\"search() requires either 'query' or 'queries'\");\n      }\n      // Normalize collection/collections\n      const collections = [\n        ...(opts.collection ? [opts.collection] : []),\n        ...(opts.collections ?? []),\n      ];\n      const skipRerank = opts.rerank === false;\n\n      if (opts.queries) {\n        // Pre-expanded queries — use structuredSearch\n        return structuredSearch(internal, opts.queries, {\n          collections: collections.length > 0 ? collections : undefined,\n          limit: opts.limit,\n          minScore: opts.minScore,\n          explain: opts.explain,\n          intent: opts.intent,\n          candidateLimit: opts.candidateLimit,\n          skipRerank,","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/tobi/qmd/blob/dbfd0b4736aeaf761d1a16ca8e424f071df8feb9/src/index.ts#L382-L418","documentation":"The store's search method requires either query (single string) or queries (multiple strings); calling it with neither leaves nothing to search, so it throws immediately. This is a client-side argument validation error, not a search failure.","triggerScenarios":"Calling store.search({collection: 'notes'}) with no query; passing an empty string '' as query (falsy); building opts dynamically where query ends up undefined.","commonSituations":"Optional search inputs from CLI args or HTTP handlers where the query param is missing; empty-string query from user input; refactors renaming query to q or text.","solutions":["Default the query or bail early when it's absent","Use the plural queries array for multi-query search","Validate/trim user input before calling search"],"exampleFix":"// before\nconst results = await store.search({ collection });\n// after\nif (!query?.trim()) return [];\nconst results = await store.search({ query, collection });\n","handlingStrategy":"validation","validationCode":"const q = opts.query?.trim();\nif (!q && !opts.queries?.length) return []; // or throw your own error","typeGuard":"const hasSearchTerm = (o: SearchOptions): boolean =>\n  Boolean(o.query?.trim() || o.queries?.some(q => q?.trim()));","tryCatchPattern":null,"preventionTips":["Normalize/trim user-provided queries at the edge (CLI/HTTP handler)","Default empty searches to a no-op result instead of calling the API","Use TypeScript strict null checks on the query field"],"tags":["api-misuse","validation","search"],"backgroundTag":"missing-required-parameter","analyzedSha":"dbfd0b4736aeaf761d1a16ca8e424f071df8feb9","analyzedAt":"2026-08-28T18:07:46.628Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}