{"record":{"id":"0f4b728bd3a02069","repo":"Stirling-Tools/Stirling-PDF","slug":"expected-number","errorCode":null,"errorMessage":"Expected number","messagePattern":"Expected number","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/editor/src/core/utils/bulkselection/parseSelection.ts","lineNumber":336,"sourceCode":"        return null;\n      }\n      c = sign === \"-\" ? -cVal : cVal;\n    }\n    return { k, c };\n  }\n\n  private tryReadNumber(): number | null {\n    this.skipWs();\n    const m = this.src.slice(this.idx).match(/^(\\d+)/);\n    if (!m) return null;\n    this.consume(m[1].length);\n    const num = parseInt(m[1], 10);\n    return Number.isFinite(num) ? num : null;\n  }\n\n  private readRequiredNumber(): number {\n    const n = this.tryReadNumber();\n    if (n === null) throw new Error(\"Expected number\");\n    return n;\n  }\n\n  private readWord(): string | null {\n    this.skipWs();\n    const m = this.src.slice(this.idx).match(/^([A-Za-z]+)/);\n    if (!m) return null;\n    this.consume(m[1].length);\n    return m[1];\n  }\n\n  private tryConsumeNot(): boolean {\n    const start = this.idx;\n    const word = this.readWord();\n    if (!word) {\n      this.idx = start;\n      return false;\n    }","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/core/utils/bulkselection/parseSelection.ts#L318-L354","documentation":"Thrown by readRequiredNumber when tryReadNumber returns null — i.e. the next characters are not leading digits. It is called after a '-' in a range (number '-' number), so this specifically means a range's end value is missing or non-numeric. Like sibling parser errors, it is caught by the CSV fallback unless strict mode is on.","triggerScenarios":"Input like '1-' (range with no end), '1-a' (range end is a letter), or '5-' followed by end-of-string. The parser read the start number, consumed '-', then expected digits but found none.","commonSituations":"User typed an incomplete range and submitted, or a trailing '-' was left from editing. Strict mode surfaces the error; non-strict falls back to CSV (which ignores the malformed token).","solutions":["Complete every range with an end number: 'start-end', e.g. '1-10'.","Remove a trailing '-' if a single page was intended ('1' not '1-').","Validate with a regex like /^\\d+\\s*-\\s*\\d+$/ per token before submitting in strict contexts.","Use the diagnostics warning to flag incomplete ranges before strict enforcement."],"exampleFix":"// before\nparseSelectionWithDiagnostics('1-', max, { strict: true })\n// after\nparseSelectionWithDiagnostics('1-10', max, { strict: true })","handlingStrategy":"validation","validationCode":"function rangesAreComplete(input: string): boolean {\n  return input.split(',').every(tok => !/\\d\\s*-\\s*$/.test(tok.trim()));\n}\n\nif (!rangesAreComplete(input)) {\n  showUser('Every range must have an end number (e.g. 1-10).');\n}","typeGuard":"function isCompleteRangeToken(tok: string): boolean {\n  return /^\\d+\\s*-\\s*\\d+$/.test(tok.trim()) || /^\\d+$/.test(tok.trim());\n}","tryCatchPattern":"try {\n  const { pages } = parseSelectionWithDiagnostics(input, maxPages, { strict: true });\n} catch (e) {\n  if (e instanceof Error && e.message === 'Expected number') {\n    showUser('A range is missing its end number.');\n  } else { throw e; }\n}","preventionTips":["Always provide both ends of a range ('1-10', not '1-').","Validate each comma-separated token with a regex before strict parsing.","Use non-strict mode to fall back to CSV and warn.","Show a live count of matched pages so incomplete ranges are obvious."],"tags":["bulk-selection","parser","validation","range"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}