{"record":{"id":"c4d716b56cf2cf8e","repo":"heygen-com/hyperframes","slug":"cols-must-be-a-positive-integer","errorCode":null,"errorMessage":"--cols must be a positive integer","messagePattern":"--cols must be a positive integer","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/compare.ts","lineNumber":109,"sourceCode":"  return labels;\n}\n\nfunction parseAtSeconds(value: unknown): number {\n  const raw = readOptionalString(value);\n  if (!raw) return 0;\n  const parsed = Number(raw);\n  if (!Number.isFinite(parsed) || parsed < 0) {\n    throw new Error(\"--at must be a non-negative number of seconds\");\n  }\n  return parsed;\n}\n\nfunction parseColumns(value: unknown): number | undefined {\n  const raw = readOptionalString(value);\n  if (!raw) return undefined;\n  const parsed = Number(raw);\n  if (!Number.isInteger(parsed) || parsed < 1) {\n    throw new Error(\"--cols must be a positive integer\");\n  }\n  return parsed;\n}\n\nfunction defaultCompareCols(cellCount: number): number {\n  return Math.max(1, Math.min(MAX_COLUMNS, Math.ceil(Math.sqrt(cellCount))));\n}\n\nexport function parseCompareArgs(\n  args: {\n    _?: readonly unknown[];\n    labels?: unknown;\n    out?: unknown;\n    at?: unknown;\n    cols?: unknown;\n    json?: unknown;\n    timeout?: unknown;\n  },","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/compare.ts#L91-L127","documentation":"Thrown by parseColumns() in the `compare` command when --cols fails its integer check. The value is run through Number(raw), then rejected unless Number.isInteger(parsed) AND parsed >= 1. An empty/whitespace value never reaches here because readOptionalString returns undefined first. There is no upper bound enforced at this layer (defaultCompareCols later caps the auto-computed default at MAX_COLUMNS=4, but an explicit --cols accepts any positive integer).","triggerScenarios":"Passing `--cols 0` (fails the < 1 check), `--cols -1`, `--cols 2.5` (not an integer), `--cols abc` (Number yields NaN, not an integer), `--cols 1.5e1` (15, actually passes). Note `--cols 3.0` passes because Number('3.0')===3, and `--cols ' 3 '` passes because Number trims whitespace.","commonSituations":"Assuming 0 disables the grid; passing a float column count; a typo or shell variable expansion producing a non-numeric string; copying a value from a UI that emits decimals.","solutions":["Pass a whole number >= 1, e.g. --cols 2 or --cols 4","Omit --cols entirely to use the sqrt-based default (capped at 4)","If the value comes from a variable, coerce with Math.max(1, Math.trunc(Number(v))) before passing"],"exampleFix":"// before\nhyperframes compare ./a ./b --cols 0\n// after\nhyperframes compare ./a ./b --cols 2","handlingStrategy":"validation","validationCode":"function parseColsSafe(raw: string | undefined): number | undefined {\n  if (!raw) return undefined;\n  const n = Number(raw);\n  if (!Number.isInteger(n) || n < 1) {\n    throw new Error(`--cols must be a positive integer (got ${JSON.stringify(raw)})`);\n  }\n  return n;\n}","typeGuard":"function isPositiveIntegerInput(raw: unknown): raw is string {\n  return typeof raw === 'string' &&\n    raw.trim().length > 0 &&\n    Number.isInteger(Number(raw)) &&\n    Number(raw) >= 1;\n}","tryCatchPattern":null,"preventionTips":["Coerce dynamic values with Math.max(1, Math.trunc(Number(v))) before passing to --cols","Omit --cols to accept the sqrt-based default rather than guessing","Validate the value in your wrapper script before invoking the CLI"],"tags":["cli-args","validation","compare","integer"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}