santifer/career-ops · error · RangeError

Reservation count must be an integer from 1 to ${MAX_COUNT}

Error message

Reservation count must be an integer from 1 to ${MAX_COUNT}

What it means

reserveReportNumbers(count, options) reserves `count` contiguous report IDs under a tracker lock. It throws a RangeError when count is not an integer in [1, MAX_COUNT] where MAX_COUNT = 50. The upper bound prevents runaway reservations and oversized lock hold times.

Source

Thrown at reserve-report-num.mjs:158

  if (!Number.isSafeInteger(pid) || pid <= 0) return false;
  try {
    process.kill(pid, 0);
    return true;
  } catch (err) {
    return err?.code === 'EPERM';
  }
}

/**
 * Reserve one or more contiguous report IDs.
 *
 * @param {number} [count=1] Number of IDs to reserve (1-50).
 * @param {object} [options] Path and lock overrides.
 * @returns {Promise<number[]>} Reserved numeric IDs.
 */
export async function reserveReportNumbers(count = 1, options = {}) {
  if (!Number.isInteger(count) || count < 1 || count > MAX_COUNT) {
    throw new RangeError(`Reservation count must be an integer from 1 to ${MAX_COUNT}`);
  }

  const reportsDir = reportsDirFor(options);
  const trackerPath = trackerPathFor(options);
  mkdirSync(reportsDir, { recursive: true });

  const lock = await acquireTrackerLock(trackerLockDirFor(trackerPath), {
    timeoutMs: Number(process.env.CAREER_OPS_TRACKER_LOCK_TIMEOUT_MS) || 60_000,
    retryMs: Number(process.env.CAREER_OPS_TRACKER_LOCK_RETRY_MS) || 75,
    staleMs: Number(process.env.CAREER_OPS_TRACKER_LOCK_STALE_MS) || 10 * 60_000,
    tracker: trackerPath,
    ...options.lockOptions,
  });

  try {
    let occupied = collectOccupied(reportsDir, trackerPath);
    let base = highestNumber(occupied) + 1;
    const token = randomUUID();

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Validate and clamp count before calling: const c = Math.min(Math.max(1, Math.trunc(Number(count))), 50).
  2. If you genuinely need more than 50 IDs, call reserveReportNumbers in multiple batches of <= 50 and concatenate results.
  3. Parse CLI --count with Number() and guard: if (!Number.isInteger(c) || c < 1 || c > 50) exit with usage.
  4. If count could be 0 (no work), skip the reserveReportNumbers call entirely rather than passing 0.

Example fix

// before
const ids = await reserveReportNumbers(workerCount); // throws if workerCount > 50

// after
const capped = Math.min(Math.max(1, Math.trunc(Number(workerCount))), 50);
const ids = await reserveReportNumbers(capped);
Defensive patterns

Strategy: validation

Validate before calling

function validateReservationCount(count) {
  const c = Number(count);
  if (!Number.isInteger(c) || c < 1 || c > 50) {
    throw new RangeError(`Reservation count must be an integer from 1 to 50`);
  }
  return c;
}
reserveReportNumbers(validateReservationCount(cliCount));

Type guard

function isValidReservationCount(value) {
  return Number.isInteger(value) && value >= 1 && value <= 50;
}

Try / catch

try {
  const ids = await reserveReportNumbers(count);
} catch (err) {
  if (err instanceof RangeError && err.message.includes('Reservation count')) {
    console.error(`--count must be 1-50, got ${count}`);
    process.exit(2);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling reserveReportNumbers(0), reserveReportNumbers(-5), reserveReportNumbers(51), reserveReportNumbers(1.5), or reserveReportNumbers(NaN). Passing an unparsed string from a --count CLI flag.

Common situations: A batch worker computing count = numberOfWorkers and exceeding 50; a CLI flag parsed as a string ('10') rather than a number; defaulting count to 0 when no workers are needed instead of skipping the call.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/26a4ed6fd9adbb92. Report an issue: GitHub.