{"record":{"id":"48c9b5b0b9a4162e","repo":"affaan-m/ECC","slug":"etimedout","errorCode":"ETIMEDOUT","errorMessage":"Codex review timed out","messagePattern":"Codex review timed out","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/council-multi-model/scripts/review-with-codex.js","lineNumber":213,"sourceCode":"  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',\n      timeout: options.timeoutMs,\n      maxBuffer: 1024 * 1024,\n      windowsHide: true,\n    });\n\n    if (result.error) {\n      if (result.error.code === 'ETIMEDOUT') throw new Error('Codex review timed out');\n      if (result.error.code === 'ENOENT') throw new Error('Codex CLI is not installed');\n      throw new Error(`Codex invocation failed: ${result.error.message}`);\n    }\n    if (result.status !== 0) {\n      const detail = (result.stderr || '').trim().split('\\n').slice(-1)[0];\n      throw new Error(`Codex review failed${detail ? `: ${detail}` : ''}`);\n    }\n\n    let text;\n    try {\n      text = readFile(outputFile, 'utf8').trim();\n    } catch (error) {\n      throw new Error(`Codex returned no final response: ${error.message}`);\n    }\n    if (!text) throw new Error('Codex returned an empty final response');\n    return `${providerLabel(options.hostProvider)}\\n${text}`;\n  } finally {\n    remove(tempDir, { recursive: true, force: true });","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/council-multi-model/scripts/review-with-codex.js#L195-L231","documentation":"After spawning the Codex CLI via spawnSync, the library inspects result.error. Node reports child-process timeouts with error.code === 'ETIMEDOUT', which occurs when the spawned process exceeds the timeout option. The library maps that to a friendly 'Codex review timed out' error instead of leaking a raw SystemError.","triggerScenarios":"runReview spawns the Codex CLI with a valid timeoutMs, the Codex process runs longer than options.timeoutMs, and Node kills it, returning result.error with code ETIMEDOUT.","commonSituations":"Very large review packets (up to MAX_PROMPT_BYTES) given a minimal 10s timeout; slow machine or cold Codex CLI startup; network-bound Codex operations with a tight 120s cap; CI runners with degraded performance.","solutions":["Increase timeoutMs (up to the 120000 ms cap) and retry the review.","Reduce the prompt size so the review completes faster.","Verify the Codex CLI responds at all: run `codex --version` manually; a hung/stale installation should be reinstalled.","Catch the error and fall back to another review provider in the council setup.","Check machine load/CI concurrency; Codex may simply be starved of CPU."],"exampleFix":"// before\nawait runReview({ prompt: hugePacket, consent: true, timeoutMs: 10_000 });\n// after\nawait runReview({ prompt: hugePacket.sliceSections(0, 3), consent: true, timeoutMs: 120_000 });","handlingStrategy":"retry","validationCode":"const estimateMs = (bytes) => Math.min(Math.max(bytes / 1024, 10) * 1000, 120_000);\nconst timeoutMs = Math.max(opts.timeoutMs ?? 0, estimateMs(Buffer.byteLength(prompt)));\nif (timeoutMs > 120_000) splitPrompt(prompt); // reduce work instead of raising timeout","typeGuard":null,"tryCatchPattern":"try {\n  return await runReview({ ...opts, timeoutMs: 120_000 });\n} catch (e) {\n  if (e.message === 'Codex review timed out') return fallbackProvider(opts);\n  throw e;\n}","preventionTips":["Budget timeout proportionally to prompt size; large packets need the full 120s.","Split big reviews into smaller packets instead of pushing the timeout cap.","Run `codex --version` once at startup to fail fast on a broken CLI."],"tags":["timeout","cli","subprocess","network"],"backgroundTag":"request-timeout","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"}