affaan-m/ECC · error · Error
ETIMEDOUT
ETIMEDOUT
Error message
Codex review timed out
What it means
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.
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.
Example fix
// before
await runReview({ prompt: hugePacket, consent: true, timeoutMs: 10_000 });
// after
await runReview({ prompt: hugePacket.sliceSections(0, 3), consent: true, timeoutMs: 120_000 }); Defensive patterns
Strategy: retry
Validate before calling
const estimateMs = (bytes) => Math.min(Math.max(bytes / 1024, 10) * 1000, 120_000); const timeoutMs = Math.max(opts.timeoutMs ?? 0, estimateMs(Buffer.byteLength(prompt))); if (timeoutMs > 120_000) splitPrompt(prompt); // reduce work instead of raising timeout
Try / catch
try {
return await runReview({ ...opts, timeoutMs: 120_000 });
} catch (e) {
if (e.message === 'Codex review timed out') return fallbackProvider(opts);
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Codex invocation failed
- failed
- failed
- Command " " terminated by signal
- remote import host could not be resolved
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/48c9b5b0b9a4162e.
Report an issue: GitHub.
Appendix: source
Thrown at skills/council-multi-model/scripts/review-with-codex.js:213
const makeTemp = dependencies.mkdtempSync || fs.mkdtempSync;
const readFile = dependencies.readFileSync || fs.readFileSync;
const remove = dependencies.rmSync || fs.rmSync;
const tempDir = makeTemp(path.join(os.tmpdir(), 'ecc-council-review-'));
const outputFile = path.join(tempDir, 'last-message.txt');
try {
const result = spawn('codex', buildCodexArgs(tempDir, outputFile), {
cwd: tempDir,
env: environment,
input: prompt,
encoding: 'utf8',
timeout: options.timeoutMs,
maxBuffer: 1024 * 1024,
windowsHide: true,
});
if (result.error) {
if (result.error.code === 'ETIMEDOUT') throw new Error('Codex review timed out');
if (result.error.code === 'ENOENT') throw new Error('Codex CLI is not installed');
throw new Error(`Codex invocation failed: ${result.error.message}`);
}
if (result.status !== 0) {
const detail = (result.stderr || '').trim().split('\n').slice(-1)[0];
throw new Error(`Codex review failed${detail ? `: ${detail}` : ''}`);
}
let text;
try {
text = readFile(outputFile, 'utf8').trim();
} catch (error) {
throw new Error(`Codex returned no final response: ${error.message}`);
}
if (!text) throw new Error('Codex returned an empty final response');
return `${providerLabel(options.hostProvider)}\n${text}`;
} finally {
remove(tempDir, { recursive: true, force: true });View on GitHub (pinned to 8321021c54)