tobi/qmd · error · Error

Line ${line.number}: only one intent: line is allowed per be

Error message

Line ${line.number}: only one intent: line is allowed per benchmark query.

What it means

Thrown by parseStructuredQuery in src/bench/bench.ts when a benchmark fixture query document contains more than one 'intent:' line. Each multi-line query in a bench fixture may carry at most a single intent annotation; the second occurrence aborts parsing.

Source

Thrown at src/bench/bench.ts:62

};

function parseStructuredQuery(query: string): ParsedStructuredQuery | undefined {
  const lines = query.split("\n").map((line, idx) => ({
    trimmed: line.trim(),
    number: idx + 1,
  })).filter(line => line.trimmed.length > 0);

  if (lines.length === 0) return undefined;

  const prefixRe = /^(lex|vec|hyde):\s*/i;
  const intentRe = /^intent:\s*/i;
  const searches: ExpandedQuery[] = [];
  let intent: string | undefined;

  for (const line of lines) {
    if (intentRe.test(line.trimmed)) {
      if (intent !== undefined) {
        throw new Error(`Line ${line.number}: only one intent: line is allowed per benchmark query.`);
      }
      intent = line.trimmed.replace(intentRe, "").trim();
      if (!intent) {
        throw new Error(`Line ${line.number}: intent: must include text.`);
      }
      continue;
    }

    const match = line.trimmed.match(prefixRe);
    if (match) {
      const type = match[1]!.toLowerCase() as "lex" | "vec" | "hyde";
      const text = line.trimmed.slice(match[0].length).trim();
      if (!text) {
        throw new Error(`Line ${line.number} (${type}:) must include text.`);
      }
      searches.push({ type, query: text, line: line.number });
      continue;
    }

View on GitHub (pinned to dbfd0b4736)

Solutions

  1. Delete the duplicate intent: line so exactly one remains per query document
  2. Merge the two intent descriptions into a single intent: line
  3. Run qmd bench with a small fixture to validate syntax before the full run

Example fix

// before
"lex: install steps\nintent: setup help\nintent: installation docs"
// after
"lex: install steps\nintent: setup and installation docs"
Defensive patterns

Strategy: validation

Validate before calling

const intentCount = (doc.match(/^\s*intent:/gm) || []).length;
if (intentCount > 1) throw new RangeError(`fixture query has ${intentCount} intent: lines; max 1`);

Type guard

const hasSingleIntent = (doc: string) => (doc.match(/^\s*intent:/gm) || []).length <= 1;

Prevention

When it happens

Trigger: A fixture JSON query whose document string has two lines starting with 'intent:', e.g. 'intent: find setup docs\nintent: find config docs\nlex: install'. Passed to runBenchmark via the fixture's queries array.

Common situations: Copy-pasting an intent line while editing bench fixtures; merging two query documents into one; appending notes that accidentally use the intent: prefix.

Related errors


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