{"record":{"id":"16b1cc55eab9b587","repo":"santifer/career-ops","slug":"no-safe-report-number-range-remains","errorCode":null,"errorMessage":"No safe report-number range remains","messagePattern":"No safe report-number range remains","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"critical","filePath":"reserve-report-num.mjs","lineNumber":195,"sourceCode":"  mkdirSync(reportsDir, { recursive: true });\n\n  const lock = await acquireTrackerLock(trackerLockDirFor(trackerPath), {\n    timeoutMs: Number(process.env.CAREER_OPS_TRACKER_LOCK_TIMEOUT_MS) || 60_000,\n    retryMs: Number(process.env.CAREER_OPS_TRACKER_LOCK_RETRY_MS) || 75,\n    staleMs: Number(process.env.CAREER_OPS_TRACKER_LOCK_STALE_MS) || 10 * 60_000,\n    tracker: trackerPath,\n    ...options.lockOptions,\n  });\n\n  try {\n    let occupied = collectOccupied(reportsDir, trackerPath);\n    let base = highestNumber(occupied) + 1;\n    const token = randomUUID();\n\n    for (let tries = 0; tries < MAX_RETRIES; tries++) {\n      const end = base + (count - 1);\n      if (!Number.isSafeInteger(base) || !Number.isSafeInteger(end)) {\n        throw new RangeError('No safe report-number range remains');\n      }\n      const claimed = [];\n      let failedAt = null;\n      for (let num = base; num <= end; num++) {\n        if (claimSlot(reportsDir, num, occupied, token)) {\n          claimed.push(num);\n        } else {\n          failedAt = num;\n          break;\n        }\n      }\n      if (failedAt == null) {\n        Object.defineProperty(claimed, RESERVATION_TOKEN, { value: token });\n        return claimed;\n      }\n\n      for (const num of claimed) releaseSlot(reportsDir, num, { token });\n      occupied = collectOccupied(reportsDir, trackerPath);","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/reserve-report-num.mjs#L177-L213","documentation":"After scanning occupied report numbers (report files, sentinels, tracker rows/links), the allocator computes base = maxOccupied + 1 and the range end. If base or end exceeds Number.MAX_SAFE_INTEGER, no safe contiguous range exists, so it throws this RangeError rather than silently allocating unsafe numeric IDs. In practice this fires only when occupied numbers are astronomically large.","triggerScenarios":"A reports/ directory or tracker containing a filename whose leading digits parse to a number near Number.MAX_SAFE_INTEGER (e.g. a timestamped filename like 1789569700000-foo.md matching /^(\\d+)-/), making highestNumber(occupied) enormous; the very first iteration then fails the isSafeInteger check.","commonSituations":"Non-report files dropped into reports/ whose names start with epoch-millisecond timestamps or large IDs. A misconfigured CAREER_OPS_REPORTS_DIR pointing at a directory of timestamp-named logs. Corrupted tracker rows with huge num or report-link numbers.","solutions":["Inspect reports/ for files whose names start with huge digit prefixes and move/rename them out of the directory (they are treated as occupied report numbers).","Set options.reportsDir / CAREER_OPS_REPORTS_DIR to the correct dedicated reports directory instead of one polluted with timestamp-named files.","Check data/applications.md for rows with absurd num values or report links like [20250601](reports/2025-06-01...) and fix them.","Note the allocator already excludes bare date files (YYYY-MM-DD.md) but not timestamp-prefixed names — rename those files to not start with digits."],"exampleFix":"// before\n$ cp /tmp/scan-2026-09-16T10-00-00.md reports/   // name starts with digits -> occupied 2026...\n// after\n$ mv /tmp/scan-2026-09-16T10-00-00.md reports/scan-digest-2026-09-16.md // no leading digits","handlingStrategy":"validation","validationCode":"import { readdirSync } from 'fs';\nconst bad = readdirSync('reports')\n  .map(name => ({ name, m: name.match(/^(\\d+)-/) }))\n  .filter(({ m }) => m && parseInt(m[1], 10) > 1e9);\nif (bad.length) throw new Error(`reports/ has non-report huge-number files: ${bad.map(b => b.name)}`);","typeGuard":null,"tryCatchPattern":"try {\n  ids = await reserveReportNumbers(count);\n} catch (err) {\n  if (err instanceof RangeError && err.message.includes('No safe report-number range')) {\n    // inspect reports/ and tracker for huge digit-prefixed filenames/rows\n  }\n  throw err;\n}","preventionTips":["Never drop files whose names start with large digit runs into reports/ — they count as occupied report numbers.","Keep CAREER_OPS_REPORTS_DIR pointed at the dedicated reports directory, not a general dump.","Audit the tracker for absurd row numbers or report links.","Remember bare YYYY-MM-DD.md files are excluded but timestamp-prefixed names are not."],"tags":["overflow","filesystem","safe-integer","data-corruption"],"backgroundTag":"value-out-of-range","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}