heygen-com/hyperframes · error · Error

--cols must be a positive integer

Error message

--cols must be a positive integer

What it means

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).

Source

Thrown at packages/cli/src/commands/compare.ts:109

  return labels;
}

function parseAtSeconds(value: unknown): number {
  const raw = readOptionalString(value);
  if (!raw) return 0;
  const parsed = Number(raw);
  if (!Number.isFinite(parsed) || parsed < 0) {
    throw new Error("--at must be a non-negative number of seconds");
  }
  return parsed;
}

function parseColumns(value: unknown): number | undefined {
  const raw = readOptionalString(value);
  if (!raw) return undefined;
  const parsed = Number(raw);
  if (!Number.isInteger(parsed) || parsed < 1) {
    throw new Error("--cols must be a positive integer");
  }
  return parsed;
}

function defaultCompareCols(cellCount: number): number {
  return Math.max(1, Math.min(MAX_COLUMNS, Math.ceil(Math.sqrt(cellCount))));
}

export function parseCompareArgs(
  args: {
    _?: readonly unknown[];
    labels?: unknown;
    out?: unknown;
    at?: unknown;
    cols?: unknown;
    json?: unknown;
    timeout?: unknown;
  },

View on GitHub (pinned to c2996c8626)

Solutions

  1. Pass a whole number >= 1, e.g. --cols 2 or --cols 4
  2. Omit --cols entirely to use the sqrt-based default (capped at 4)
  3. If the value comes from a variable, coerce with Math.max(1, Math.trunc(Number(v))) before passing

Example fix

// before
hyperframes compare ./a ./b --cols 0
// after
hyperframes compare ./a ./b --cols 2
Defensive patterns

Strategy: validation

Validate before calling

function parseColsSafe(raw: string | undefined): number | undefined {
  if (!raw) return undefined;
  const n = Number(raw);
  if (!Number.isInteger(n) || n < 1) {
    throw new Error(`--cols must be a positive integer (got ${JSON.stringify(raw)})`);
  }
  return n;
}

Type guard

function isPositiveIntegerInput(raw: unknown): raw is string {
  return typeof raw === 'string' &&
    raw.trim().length > 0 &&
    Number.isInteger(Number(raw)) &&
    Number(raw) >= 1;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/c4d716b56cf2cf8e. Report an issue: GitHub.