{"record":{"id":"2b5758335e197c87","repo":"chenglou/pretext","slug":"invalid-widths-parameter-raw","errorCode":null,"errorMessage":"Invalid widths parameter: ${raw}","messagePattern":"Invalid widths parameter: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pages/corpus.ts","lineNumber":273,"sourceCode":"const diagnosticGraphemeSegmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n\nlet corpusList: CorpusMeta[] = []\nlet currentMeta: CorpusMeta | null = null\nlet currentText = ''\nlet currentPrepared: PreparedTextWithSegments | null = null\nlet currentSliceStart: number | null = null\nlet currentSliceEnd: number | null = null\n\nfunction parseWidthList(raw: string | null): number[] | null {\n  if (raw === null) return null\n\n  const widths = raw\n    .split(',')\n    .map(part => Number.parseInt(part.trim(), 10))\n    .filter(width => Number.isFinite(width))\n\n  if (widths.length === 0) {\n    throw new Error(`Invalid widths parameter: ${raw}`)\n  }\n\n  return [...new Set(widths)]\n}\n\nfunction withRequestId<T extends CorpusReport>(report: T): CorpusReport {\n  return requestId === undefined ? report : { ...report, requestId }\n}\n\nfunction toNavigationReport(report: CorpusReport): CorpusReport {\n  if (report.rows === undefined) return report\n  const { rows: _rows, ...navigationReport } = report\n  return navigationReport\n}\n\nfunction getEnvironmentFingerprint(): EnvironmentFingerprint {\n  return {\n    userAgent: navigator.userAgent,","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/chenglou/pretext/blob/ac49b09b7d83ede19581fa94a8b892b07d309baf/pages/corpus.ts#L255-L291","documentation":"Thrown by parseWidthList() while parsing the ?widths= URL query parameter on the corpus page. The function splits the raw value on commas, trims each token, parses each with Number.parseInt, and keeps only finite results; if every token fails to parse to a finite integer it throws. This runs at module top-level (corpus.ts:225), so it aborts page initialization before any corpus loads. An absent parameter returns null and does NOT throw — only a present-but-empty-or-non-numeric value does.","triggerScenarios":"Loading /corpus?widths= (empty value), /corpus?widths=abc, /corpus?widths=,,, (only separators), or /corpus?widths=foo,bar. Each token is individually parseInt'd; if none yield a finite number the guard trips. A mix like ?widths=abc,400 does not throw because 400 survives the filter.","commonSituations":"A bookmarked or hand-edited URL with a typo in the widths param; an automation harness constructing the widths query string from an empty/undefined variable; copying a URL fragment where the widths value got truncated. The parameter is only used to drive the multi-width sweep path (getRequestedSweepWidths), so misformed values block the sweep landing page.","solutions":["Remove or fix the ?widths= parameter in the URL so it contains at least one integer (e.g. ?widths=300,400,500).","If you do not need a sweep, drop the widths param entirely — parseWidthList receives null and returns null, and the page falls back to a single width.","If a script is generating the URL, coerce each width to a finite integer and skip the param when the list is empty rather than emitting ?widths=.","URL-encode the value only after validating it matches /^\\d+(,\\d+)*$/."],"exampleFix":"// before\nconst url = `/corpus?widths=${widthsParam}`\n\n// after\nconst safeWidths = (widthsParam && /\\d+(,\\d+)*/.test(widthsParam)) ? widthsParam : ''\nconst url = `/corpus${safeWidths ? `?widths=${safeWidths}` : ''}`","handlingStrategy":"validation","validationCode":"// Validate the widths query param before constructing the URL.\nfunction buildWidthsParam(widths: number[] | null | undefined): string {\n  if (widths === null || widths === undefined) return ''\n  const clean = widths.filter(w => Number.isInteger(w) && w > 0)\n  return clean.length > 0 ? `?widths=${clean.join(',')}` : ''\n}","typeGuard":"// Reject anything that would yield zero finite integers after split/parse.\nfunction isValidWidthsParam(raw: string): boolean {\n  if (raw.length === 0) return false\n  return raw.split(',').every(part => /^\\d+$/.test(part.trim())) &&\n    raw.split(',').length > 0\n}","tryCatchPattern":"// parseWidthList runs at module top-level and cannot be try/catch'd by the page.\n// Validate the URL before navigation instead:\nconst widthsRaw = new URLSearchParams(location.search).get('widths')\nif (widthsRaw !== null && !isValidWidthsParam(widthsRaw)) {\n  // strip the bad param and reload, or show an error state\n  const clean = new URLSearchParams(location.search)\n  clean.delete('widths')\n  history.replaceState(null, '', `?${clean.toString()}`)\n}","preventionTips":["Never interpolate a possibly-empty variable into the widths param; omit the param entirely when empty.","When automating, build the widths param from a validated number[] and join with commas.","Treat absence (null) and emptiness ('') differently — absence is valid, emptiness is not."],"tags":["url-param","validation","corpus-page","config"],"backgroundTag":null,"analyzedSha":"ac49b09b7d83ede19581fa94a8b892b07d309baf","analyzedAt":"2026-08-12T17:03:16.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}