jackwener/OpenCLI · error · ArgumentError

${name} must be a positive integer

Error message

${name} must be a positive integer

What it means

requireLimit validates that a numeric limit argument is a positive integer before it is sent to the Pinterest API. It throws this ArgumentError when the value (or its fallback) is missing, non-numeric, non-integer, or <= 0. The library throws instead of silently clamping so callers get an immediate, actionable CLI-style error.

Source

Thrown at clis/pinterest/utils.js:30

/** Resource actions that mutate; only these treat a 403 as "you need to log in". */
const WRITE_ACTIONS = new Set(['create', 'update', 'delete']);

/** Unwrap the { session, data } envelope some browser-bridge versions add. */
export function unwrapEvaluateResult(payload) {
  const isEnvelope = payload
    && typeof payload === 'object'
    && !Array.isArray(payload)
    && 'session' in payload
    && 'data' in payload;
  return isEnvelope ? payload.data : payload;
}

/** Validate a positive-integer limit (throws instead of silently clamping). */
export function requireLimit(value, { fallback, max, name = 'limit' }) {
  const parsed = Number(value ?? fallback);
  if (!Number.isInteger(parsed) || parsed <= 0) {
    throw new ArgumentError(`${name} must be a positive integer`, `e.g. --${name} 10`);
  }
  if (max && parsed > max) {
    throw new ArgumentError(`${name} must be <= ${max}`, `Lower --${name} to ${max} or below`);
  }
  return parsed;
}

/**
 * Fold a slug for comparison. Pinterest keeps non-ASCII characters in slugs (e.g.
 * `naive-café-中文`) and stores them NFC, but a pasted or keyboard-composed accent can arrive as
 * NFD, which compares unequal byte-wise.
 */
export function normalizeForMatch(value) {
  return String(value ?? '').normalize('NFC').trim().toLowerCase().replace(/\s+/g, ' ');
}

/**
 * Pinterest path prefixes that are site routes, not usernames. Without this a pin URL parses as

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a positive whole number, e.g. requireLimit(10, { max: 100 })
  2. Supply a valid fallback option, e.g. requireLimit(input, { fallback: 25 }) so missing input resolves to a default
  3. Trim/parse CLI strings first (Number(value)) and reject NaN before calling
  4. If you intended a hard cap, also pass max so oversized values are caught separately

Example fix

// before
const limit = requireLimit(opts.limit);
// after
const limit = requireLimit(opts.limit ?? 25, { max: 100, name: 'limit' });
Defensive patterns

Strategy: validation

Validate before calling

function isValidLimit(v) {
  const n = Number(v);
  return Number.isSafeInteger(n) && n > 0;
}
if (!isValidLimit(input)) input = 25; // default before calling requireLimit

Type guard

const isPositiveInt = (v) => typeof v === 'number' && Number.isSafeInteger(v) && v > 0;

Try / catch

let limit;
try {
  limit = requireLimit(input, { fallback: 25, max: 100 });
} catch (err) {
  if (err instanceof ArgumentError) {
    console.error(`${err.message} — ${err.hint}`);
    limit = 25;
  } else throw err;
}

Prevention

When it happens

Trigger: Calling requireLimit (via the limit helper) with e.g. limit('abc'), limit(0), limit(-5), limit(2.5), or undefined with no fallback — anything where Number(value ?? fallback) is not an integer > 0.

Common situations: Passing a CLI flag like --limit from a shell where it was left empty or contained a suffix ('10s'); deriving a limit from parseFloat() of user text; typos like 'lmit'; using 0 or negative values expecting them to mean 'unlimited'.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/5fbc60f9f14a7474. Report an issue: GitHub.