chenglou/pretext · error · Error

--step must be > 0

Error message

--step must be > 0

What it means

Thrown by parseOptions in corpus-font-matrix.ts after parsing the width-sweep bounds. --step is the pixel increment between sweep widths (default 10); it must be strictly positive or the loop would be infinite / degenerate. The check fires before the --end >= --start check, so an invalid step is reported first.

Source

Thrown at scripts/corpus-font-matrix.ts:369

  }
  return browser
}

async function loadSources(): Promise<CorpusMeta[]> {
  return await Bun.file('corpora/sources.json').json()
}

function parseOptions(): MatrixOptions {
  const id = parseStringFlag('id')
  if (id === null) {
    throw new Error(`Missing --id. Available corpora: ${Object.keys(FONT_MATRIX).join(', ')}`)
  }

  const samples = parseOptionalNumberFlag('samples')
  const start = parseNumberFlag('start', 300)
  const end = parseNumberFlag('end', 900)
  const step = parseNumberFlag('step', 10)
  if (step <= 0) throw new Error('--step must be > 0')
  if (end < start) throw new Error('--end must be >= --start')

  return {
    id,
    browser: parseBrowser(parseStringFlag('browser')),
    port: parseNumberFlag('port', Number.parseInt(process.env['CORPUS_CHECK_PORT'] ?? '0', 10)),
    timeoutMs: parseNumberFlag('timeout', Number.parseInt(process.env['CORPUS_CHECK_TIMEOUT_MS'] ?? '180000', 10)),
    output: parseStringFlag('output'),
    samples,
    start,
    end,
    step,
  }
}

function getSweepWidths(meta: CorpusMeta, options: MatrixOptions): number[] {
  const min = Math.max(options.start, meta.min_width ?? options.start)
  const max = Math.min(options.end, meta.max_width ?? options.end)

View on GitHub (pinned to ac49b09b7d)

Solutions

  1. Pass a positive integer step (default 10): `--step=10`, `--step=5`, `--step=1`.
  2. Never pass a fractional step — parseInt will floor it before this check, and `--step=0.5` becomes 0 silently and would already have thrown at parseInt (it doesn't: parseInt('0.5') is 0, which then fails `step <= 0`).
  3. If you need finer-than-1px resolution, that is not supported by the integer-width sweep model — extend getSweepWidths.

Example fix

// before
bun run scripts/corpus-font-matrix.ts --id=ja-kumo-no-ito --step=0
// after
bun run scripts/corpus-font-matrix.ts --id=ja-kumo-no-ito --step=10
Defensive patterns

Strategy: validation

Validate before calling

function parseStep(raw: string | null): number {
  const step = raw === null ? 10 : Number.parseInt(raw, 10)
  if (!Number.isFinite(step) || step <= 0) {
    throw new Error(`--step must be a positive integer, got ${JSON.stringify(raw)}`)
  }
  return step
}

Type guard

function isPositiveInteger(value: string): boolean {
  return /^\d+$/.test(value) && Number.parseInt(value, 10) > 0
}

Prevention

When it happens

Trigger: parseNumberFlag('step', 10) returns a value <= 0. Throw on `--step=0`, `--step=-10`. Note `--step=0.5` parses as 0 via parseInt (no throw here, but produces an infinite loop downstream — parseInt's truncation turns a small positive into zero).

Common situations: Passing `--step=0` to mean "every width" (use 1 instead); negative steps from a sign error in a computed shell value; fractional steps (`0.5`) that parseInt silently floors to 0 — this is a footgun: the check does not catch it because the parse already happened upstream.

Related errors


AI-assisted analysis of chenglou/pretext@ac49b09b7d (2026-08-12). Data as JSON: /api/errors/2ff3bfa2ac3df5f4. Report an issue: GitHub.