tobi/qmd · error · Error

${location} (${search.type}): queries must be single-line. R

Error message

${location} (${search.type}): queries must be single-line. Remove newline characters.

What it means

The multi-search validator rejects any query containing \r or \n because each search's query must fit on a single line (they are interpolated into single-line SQL/FTS statements). The error is prefixed with the search's line number or 'Structured search'.

Source

Thrown at src/store.ts:5883

  options?: StructuredSearchOptions
): Promise<HybridQueryResult[]> {
  const limit = options?.limit ?? 10;
  const minScore = options?.minScore ?? 0;
  const candidateLimit = options?.candidateLimit ?? RERANK_CANDIDATE_LIMIT;
  const explain = options?.explain ?? false;
  const intent = options?.intent;
  const skipRerank = options?.skipRerank ?? false;
  const hooks = options?.hooks;

  const collections = options?.collections;

  if (searches.length === 0) return [];

  // Validate queries before executing
  for (const search of searches) {
    const location = search.line ? `Line ${search.line}` : 'Structured search';
    if (/[\r\n]/.test(search.query)) {
      throw new Error(`${location} (${search.type}): queries must be single-line. Remove newline characters.`);
    }
    if (search.type === 'lex') {
      const error = validateLexQuery(search.query);
      if (error) {
        throw new Error(`${location} (lex): ${error}`);
      }
    } else if (search.type === 'vec' || search.type === 'hyde') {
      const error = validateSemanticQuery(search.query);
      if (error) {
        throw new Error(`${location} (${search.type}): ${error}`);
      }
    }
  }

  const rankedLists: RankedResult[][] = [];
  const rankedListMeta: RankedListMeta[] = [];
  const docidMap = new Map<string, string>(); // filepath -> docid
  const hasVectors = !!store.db.prepare(

View on GitHub (pinned to dbfd0b4736)

Solutions

  1. Strip newlines before passing: query.replace(/[\r\n]+/g, ' ').trim()
  2. Split multi-line input into separate search entries if each line is a distinct query
  3. Validate input client-side before calling searchMulti

Example fix

// before
searchMulti([{ type: 'lex', query: multiLineString }]);
// after
searchMulti([{ type: 'lex', query: multiLineString.replace(/[\r\n]+/g, ' ').trim() }]);
Defensive patterns

Strategy: validation

Validate before calling

const clean = q.replace(/[\r\n]+/g, ' ').trim(); if (!/[\r\n]/.test(clean)) searchMulti([{ type, query: clean }]);

Type guard

const isSingleLine = (q: string) => !/[\r\n]/.test(q);

Prevention

When it happens

Trigger: Passing a searches array where any entry's query string contains a newline — e.g. a template literal spanning lines, or a user query pasted with a trailing newline into searchMulti().

Common situations: Multi-line JS template strings used for queries; user input from textareas passed directly; log/env strings with embedded \n.

Related errors


AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28). Data as JSON: /api/errors/2c344f4d7b2e43e9. Report an issue: GitHub.