Stirling-Tools/Stirling-PDF · warning · Error

Unexpected trailing input

Error message

Unexpected trailing input

What it means

Thrown by ExpressionParser.parse when, after successfully parsing a top-level disjunction and skipping whitespace, the parser index has not reached the end of the string — meaning there are leftover characters the grammar cannot consume. Note: the public parseSelection() wraps this in try/catch and silently falls back to CSV, so this error only propagates to callers via parseSelectionWithDiagnostics with the strict option enabled.

Source

Thrown at frontend/editor/src/core/utils/bulkselection/parseSelection.ts:130

}

class ExpressionParser {
  private readonly src: string;
  private readonly max: number;
  private idx: number = 0;

  constructor(source: string, maxPages: number) {
    this.src = source;
    this.max = maxPages;
  }

  parse(): Set<number> {
    this.skipWs();
    const set = this.parseDisjunction();
    this.skipWs();
    // If there are leftover non-space characters, treat as error
    if (this.idx < this.src.length) {
      throw new Error("Unexpected trailing input");
    }
    return set;
  }

  private parseDisjunction(): Set<number> {
    let left = this.parseConjunction();
    while (true) {
      this.skipWs();
      const op = this.peekWordOrSymbol();
      if (!op) break;
      if (op.type === "symbol" && (op.value === "," || op.value === "|")) {
        this.consume(op.length);
        const right = this.parseConjunction();
        left = union(left, right);
        continue;
      }
      if (op.type === "word" && op.value === "or") {
        this.consume(op.length);

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Check the input immediately after the last valid token for stray characters or unsupported separators.
  2. Replace unsupported separators with the grammar's operators: ',' or '|' for OR, '&' or 'and' for conjunction.
  3. If using parseSelectionWithDiagnostics, handle the returned warning field instead of enabling strict mode unless you want hard failures.
  4. Trim and sanitize the input before parsing.

Example fix

// before
parseSelectionWithDiagnostics('1-5 ; 7', max, { strict: true })
// after
parseSelectionWithDiagnostics('1-5, 7', max, { strict: true })
Defensive patterns

Strategy: validation

Validate before calling

import { parseSelectionWithDiagnostics } from '@app/utils/bulkselection/parseSelection';

// Use non-strict mode to get a warning instead of a throw:
const { pages, warning } = parseSelectionWithDiagnostics(input, maxPages);
if (warning) showUser(warning);
// pages still contains the CSV-fallback result.

Type guard

function looksLikeCompleteExpression(input: string): boolean {
  // Reject inputs with characters outside the supported grammar
  return /^[-(),|&!\s\dA-Za-z+*n]+$/.test(input);
}

Try / catch

try {
  const { pages } = parseSelectionWithDiagnostics(input, maxPages, { strict: true });
} catch (e) {
  if (e instanceof Error && e.message === 'Unexpected trailing input') {
    showUser('Check for stray characters after your selection.');
  } else { throw e; }
}

Prevention

When it happens

Trigger: Input like '1-5 xyz' (parser consumes '1-5', then 'xyz' is leftover), '1,2;3' (semicolons not in grammar), or '1 2' (two numbers with no operator between them). Any input where the valid prefix parses but trailing tokens remain that are not operators or whitespace.

Common situations: User types a page selection with a stray character, an unsupported separator (e.g. ';'), or pastes a selection from another tool that uses different syntax. Strict mode is enabled in a bulk-selection input, so the fallback is bypassed and the raw error surfaces.

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/9dc96fa657573faf. Report an issue: GitHub.