affaan-m/ECC · warning

${flagName} must be a positive integer

Error message

${flagName} must be a positive integer

What it means

readPositiveInteger delegates to readPositiveNumber and then additionally requires Number.isInteger, rejecting fractions and NaN. It backs the flags that conceptually count things: --limit and --watch-count. A value like 1.5 or '3.0' parsed loosely will throw here.

Source

Thrown at scripts/loop-status.js:59

  const value = args[index + 1];
  if (!value || value.startsWith('--')) {
    throw new Error(`${flagName} requires a value`);
  }
  return value;
}

function readPositiveNumber(value, flagName) {
  const number = Number(value);
  if (!Number.isFinite(number) || number <= 0) {
    throw new Error(`${flagName} must be a positive number`);
  }
  return number;
}

function readPositiveInteger(value, flagName) {
  const number = readPositiveNumber(value, flagName);
  if (!Number.isInteger(number)) {
    throw new Error(`${flagName} must be a positive integer`);
  }
  return number;
}

function parseArgs(argv) {
  const args = argv.slice(2);
  const options = {
    bashTimeoutSeconds: DEFAULT_BASH_TIMEOUT_SECONDS,
    exitCode: false,
    home: null,
    json: false,
    limit: DEFAULT_LIMIT,
    now: null,
    showHelp: false,
    transcriptPaths: [],
    watch: false,
    watchCount: null,
    wakeGraceMultiplier: DEFAULT_WAKE_GRACE_MULTIPLIER,

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Pass a positive integer: `--limit 50`, `--watch-count 10`.
  2. Floor/truncate computed values before passing: `--limit "$(( TOTAL / STEP ))"`.
  3. If you truly want fractional behaviour, switch to a flag backed by readPositiveNumber.
  4. Omit the flag to use DEFAULT_LIMIT / the watch default.

Example fix

# before
node scripts/loop-status.js --limit 25.5

# after
node scripts/loop-status.js --limit 25
Defensive patterns

Strategy: validation

Validate before calling

function isPositiveInt(v) { const n = Number(v); return Number.isInteger(n) && n > 0; }
function validateCounts(flagMap) {
  for (const [flag, raw] of Object.entries(flagMap)) {
    if (raw !== undefined && !isPositiveInt(raw)) throw new Error(`${flag} must be a positive integer`);
  }
}

Type guard

/** @returns {n is number} */
function isPositiveIntGuard(n) { return Number.isInteger(n) && n > 0; }

Try / catch

try { parseArgs(process.argv); }
catch (err) { if (/must be a positive integer/.test(err.message)) { console.error(err.message); printHelp(2); } else throw err; }

Prevention

When it happens

Trigger: Passing a fractional count: `--limit 1.5` or `--watch-count 2.5`. Passing a non-integer string like 'abc' or ''. Passing 0 or a negative integer (caught first by the >0 check in readPositiveNumber).

Common situations: Scripting a computed value that occasionally yields a float, e.g. `--limit $((total/2))` where total is odd (this stays integer, but expressions using bc/awk can leak decimals). Copying a decimal from a config that mixed up --limit with --watch-interval-seconds.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/fbe4e55d8e3fe1be. Report an issue: GitHub.