{"record":{"id":"51a376d8107267dc","repo":"Hmbown/CodeWhale","slug":"days-must-be-an-integer-from-1-through-90","errorCode":null,"errorMessage":"--days must be an integer from 1 through 90","messagePattern":"--days must be an integer from 1 through 90","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"telemetry-ingest/scripts/report-active-installs.mjs","lineNumber":50,"sourceCode":"  // window that fills both sides of the 7-day trend.\n  let days = 15;\n  let json = false;\n  for (let index = 0; index < argv.length; index += 1) {\n    const arg = argv[index];\n    if (arg === \"--json\") {\n      json = true;\n      continue;\n    }\n    if (arg === \"--days\") {\n      const raw = argv[index + 1];\n      index += 1;\n      days = Number(raw);\n      continue;\n    }\n    throw new Error(`unknown argument: ${arg}`);\n  }\n  if (!Number.isInteger(days) || days < 1 || days > 90) {\n    throw new Error(\"--days must be an integer from 1 through 90\");\n  }\n  return { days, json };\n}\n\nexport function activeInstallsSql(days) {\n  return `SELECT\n  toDate(timestamp) AS day,\n  count(DISTINCT index1) AS active_installs,\n  sum(_sample_interval) AS sessions_started\nFROM codewhale_telemetry\nWHERE timestamp >= toStartOfDay(NOW()) - INTERVAL '${days - 1}' DAY\n  AND blob1 = 'session_start'\nGROUP BY day\nORDER BY day DESC\nFORMAT JSON`;\n}\n\n/** Newest ingested event of any kind — how stale the dataset is. */","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/telemetry-ingest/scripts/report-active-installs.mjs#L32-L68","documentation":"parseArgs requires the --days value to be an integer between 1 and 90 inclusive (Number.isInteger(days) && days >= 1 && days <= 90). This bounds the active-installs report to a sane window; anything outside — non-numeric text, floats, 0, negatives, or values beyond 90 — throws this error.","triggerScenarios":"--days followed by a missing or non-numeric value (Number(undefined) => NaN, Number('abc') => NaN), a decimal like 7.5, 0, a negative number, or an integer greater than 90 such as --days 365.","commonSituations":"Forgetting the value after --days; passing 'week' or '1m' instead of a number; trying a year-long report and hitting the 90-day cap; locale-formatted numbers like '7,5'.","solutions":["Pass a plain integer between 1 and 90: --days 30.","Ensure a value actually follows --days (a missing value becomes NaN).","If you need a longer window, run the report multiple times (e.g. several 90-day spans) or adjust the 1–90 bound in parseArgs deliberately.","Validate/normalize the number in the wrapper script before invoking (Number.isInteger check)."],"exampleFix":"// before\nnode scripts/report-active-installs.mjs --days 365\n// after\nnode scripts/report-active-installs.mjs --days 90","handlingStrategy":"validation","validationCode":"const days = Number(process.argv[process.argv.indexOf('--days') + 1]);\nif (!Number.isInteger(days) || days < 1 || days > 90) {\n  console.error('--days must be an integer from 1 through 90');\n}","typeGuard":"const isReportWindow = (n) => Number.isInteger(n) && n >= 1 && n <= 90;","tryCatchPattern":"try {\n  await main(process.argv.slice(2));\n} catch (err) {\n  if (err.message.startsWith('--days must be')) {\n    console.error('example: --days 30 (integer, 1-90)'); process.exit(2);\n  }\n  throw err;\n}","preventionTips":["Always supply an integer immediately after --days.","Clamp wrapper-script day windows to [1, 90] before invoking.","Never pass identifiers like 'week' or '1m'; convert to days in the caller.","Remember missing values become NaN and are rejected."],"tags":["cli","argument-validation","range-check","days"],"backgroundTag":"argument-out-of-range","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}