{"record":{"id":"a96f334bd756a5a1","repo":"affaan-m/ECC","slug":"timeout-is-outside-the-10-120-second-safety-range","errorCode":null,"errorMessage":"timeout is outside the 10-120 second safety range","messagePattern":"timeout is outside the 10-120 second safety range","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/council-multi-model/scripts/review-with-codex.js","lineNumber":188,"sourceCode":"\nfunction buildEnvironment(sourceEnv = process.env) {\n  const allowed = [\n    'PATH', 'HOME', 'USERPROFILE', 'CODEX_HOME',\n    'TMPDIR', 'TMP', 'TEMP', 'SystemRoot', 'ComSpec', 'PATHEXT',\n  ];\n  return Object.fromEntries(\n    allowed.filter((name) => sourceEnv[name]).map((name) => [name, sourceEnv[name]])\n  );\n}\n\nfunction runReview(prompt, options, dependencies = {}) {\n  if (!prompt.trim()) throw new Error('review packet is empty');\n  if (Buffer.byteLength(prompt, 'utf8') > MAX_PROMPT_BYTES) {\n    throw new Error(`review packet exceeds ${MAX_PROMPT_BYTES} bytes`);\n  }\n  if (!options.consent) throw new Error('OpenAI transfer consent is required');\n  if (options.timeoutMs < 10_000 || options.timeoutMs > MAX_TIMEOUT_MS) {\n    throw new Error('timeout is outside the 10-120 second safety range');\n  }\n\n  const spawn = dependencies.spawnSync || spawnSync;\n  const environment = buildEnvironment(dependencies.env || process.env);\n  const verifySupport = dependencies.verifyToollessSupport || verifyToollessSupport;\n  verifySupport({ spawnSync: spawn, env: environment });\n  const makeTemp = dependencies.mkdtempSync || fs.mkdtempSync;\n  const readFile = dependencies.readFileSync || fs.readFileSync;\n  const remove = dependencies.rmSync || fs.rmSync;\n  const tempDir = makeTemp(path.join(os.tmpdir(), 'ecc-council-review-'));\n  const outputFile = path.join(tempDir, 'last-message.txt');\n\n  try {\n    const result = spawn('codex', buildCodexArgs(tempDir, outputFile), {\n      cwd: tempDir,\n      env: environment,\n      input: prompt,\n      encoding: 'utf8',","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/council-multi-model/scripts/review-with-codex.js#L170-L206","documentation":"runReview validates the requested Codex subprocess timeout before spawning the CLI. Node spawnSync accepts any value, but this library deliberately confines timeouts to 10-120 seconds so a review cannot hang forever or kill Codex before it starts producing output. If options.timeoutMs is below 10000 or above MAX_TIMEOUT_MS (120000), the call is rejected before any process is started.","triggerScenarios":"Calling runReview({ ..., timeoutMs: 5000 }) or runReview({ ..., timeoutMs: 300000 }) — any value outside the inclusive 10000..120000 ms window, including undefined coerced to NaN by the comparison.","commonSituations":"Developer sets a 5-second timeout expecting a fast check; developer reuses a general-purpose 10-minute timeout constant from another tool; timeoutMs passed as a string or omitted so the numeric comparison fails.","solutions":["Set timeoutMs to a value between 10000 and 120000 milliseconds (e.g. 60000).","Clamp user-supplied values: timeoutMs = Math.min(Math.max(Number(timeoutMs) || 60000, 10000), 120000).","If a review needs more than 120s, split the prompt into smaller review packets instead of raising the timeout.","Ensure timeoutMs is a number, not a string from CLI args (use Number() before calling)."],"exampleFix":"// before\nawait runReview({ prompt, consent: true, timeoutMs: 5000 });\n// after\nawait runReview({ prompt, consent: true, timeoutMs: 60_000 }); // within 10s-120s","handlingStrategy":"validation","validationCode":"function isValidTimeout(ms) {\n  return typeof ms === 'number' && Number.isFinite(ms) && ms >= 10_000 && ms <= 120_000;\n}\nif (!isValidTimeout(opts.timeoutMs)) throw new RangeError('timeoutMs must be 10000-120000 ms');","typeGuard":"const isTimeoutMs = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 10_000 && v <= 120_000;","tryCatchPattern":"try {\n  await runReview(options);\n} catch (e) {\n  if (e.message.includes('safety range')) {\n    options.timeoutMs = 60_000;\n    await runReview(options);\n  } else throw e;\n}","preventionTips":["Define a single TIMEOUT_MS constant (60000) and derive all timeouts from it.","Clamp CLI/env-supplied timeouts with Math.min/Math.max before calling runReview.","Always convert string inputs with Number() before numeric range checks."],"tags":["validation","timeout","cli","argument-validation"],"backgroundTag":"value-out-of-range","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}