{"record":{"id":"116ca855bd2f118b","repo":"tobi/qmd","slug":"location-search-type-error","errorCode":null,"errorMessage":"${location} (${search.type}): ${error}","messagePattern":"\\$\\{location\\} \\(\\$\\{search\\.type\\}\\): \\$\\{error\\}","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/store.ts","lineNumber":5893,"sourceCode":"  const collections = options?.collections;\n\n  if (searches.length === 0) return [];\n\n  // Validate queries before executing\n  for (const search of searches) {\n    const location = search.line ? `Line ${search.line}` : 'Structured search';\n    if (/[\\r\\n]/.test(search.query)) {\n      throw new Error(`${location} (${search.type}): queries must be single-line. Remove newline characters.`);\n    }\n    if (search.type === 'lex') {\n      const error = validateLexQuery(search.query);\n      if (error) {\n        throw new Error(`${location} (lex): ${error}`);\n      }\n    } else if (search.type === 'vec' || search.type === 'hyde') {\n      const error = validateSemanticQuery(search.query);\n      if (error) {\n        throw new Error(`${location} (${search.type}): ${error}`);\n      }\n    }\n  }\n\n  const rankedLists: RankedResult[][] = [];\n  const rankedListMeta: RankedListMeta[] = [];\n  const docidMap = new Map<string, string>(); // filepath -> docid\n  const hasVectors = !!store.db.prepare(\n    `SELECT name FROM sqlite_master WHERE type='table' AND name='vectors_vec'`\n  ).get();\n\n  // Helper to run search across collections (or all if undefined)\n  const collectionList = collections ?? [undefined]; // undefined = all collections\n\n  // Step 1: Run FTS for all lex searches (sync, instant)\n  for (const search of searches) {\n    if (search.type === 'lex') {\n      for (const coll of collectionList) {","sourceCodeStart":5875,"sourceCodeEnd":5911,"githubUrl":"https://github.com/tobi/qmd/blob/dbfd0b4736aeaf761d1a16ca8e424f071df8feb9/src/store.ts#L5875-L5911","documentation":"For search entries of type 'vec' or 'hyde', validateSemanticQuery() checks the query and its error is thrown prefixed with the location and type. Typically these types require a non-empty, bounded-length query suitable for embedding.","triggerScenarios":"Passing an empty, whitespace-only, or over-limit query string with type 'vec' or 'hyde' to searchMulti().","commonSituations":"Empty user input passed through to vector search; extremely long documents pasted as the query exceeding the length cap; building searches programmatically and including blank entries.","solutions":["Filter out empty/blank queries before calling searchMulti","Truncate long queries to the model's limit","Run validateSemanticQuery first and surface its message to the user"],"exampleFix":"// before\nsearchMulti([{ type: 'vec', query: '' }]);\n// after\nsearchMulti([{ type: 'vec', query: q.trim().slice(0, 512) }].filter(s => s.query));","handlingStrategy":"validation","validationCode":"const q2 = q.trim(); if (q2 && q2.length <= LIMIT) searchMulti([{ type: 'vec', query: q2 }]);","typeGuard":"const isSemanticQueryValid = (q: string) => q.trim().length > 0 && q.length <= 2000;","tryCatchPattern":"try { searchMulti(s); } catch (e) { if (/\\(vec\\)|\\(hyde\\)/.test((e as Error).message)) return emptyResults(e); throw e; }","preventionTips":["Filter blank queries before search","Truncate long queries to the embedding limit","Validate programmatically-built search arrays"],"tags":["query","vector-search","validation"],"backgroundTag":"query-validation-failed","analyzedSha":"dbfd0b4736aeaf761d1a16ca8e424f071df8feb9","analyzedAt":"2026-08-28T18:07:46.628Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}