affaan-m/ECC · error · Error
Codex returned no final response: ${error.message}
Error message
Codex returned no final response: ${error.message} What it means
After a status-0 codex run, runReview reads the --output-last-message file (outputFile inside the temp dir). If readFile throws — file missing, permission denied, or tempDir removed — the underlying fs error is wrapped as 'Codex returned no final response: <fs message>'. It signals codex exited cleanly but did not produce the expected output artifact.
Source
Thrown at skills/council-multi-model/scripts/review-with-codex.js:226
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 });
}
}
function runStdinReview(options, dependencies = {}) {
const stdin = dependencies.stdin || process.stdin;
const stdout = dependencies.stdout || process.stdout;
const stderr = dependencies.stderr || process.stderr;
const review = dependencies.runReview || runReview;
const setExitCode = dependencies.setExitCode || ((code) => { process.exitCode = code; });
const chunks = [];
let promptBytes = 0;
let promptOverflow = false;
stdin.setEncoding('utf8');View on GitHub (pinned to 01e15490f0)
Solutions
- Confirm the installed Codex is exactly SUPPORTED_CODEX_VERSION (0.146.0), which honors --output-last-message.
- Check that os.tmpdir() is writable by the spawning process.
- Inspect the wrapped fs error message (ENOENT vs EACCES) to localize the cause.
- Reproduce with the args from buildCodexArgs and look for last-message.txt in the temp dir.
Defensive patterns
Strategy: try-catch
Try / catch
try {
return runReview(packet, options);
} catch (error) {
if (error.message.startsWith('Codex returned no final response')) {
// fs-level cause is in the message; check codex version + temp dir writability
log.error('codex produced no output file', { message: error.message });
}
throw error;
} Prevention
- Verify the installed Codex is 0.146.0, which honors --output-last-message.
- Confirm os.tmpdir() is writable by the process before invoking.
- Avoid cleaning the temp dir yourself — runReview manages it in a finally block.
When it happens
Trigger: readFile(outputFile, 'utf8') throws inside the inner try at line 223-225. The output file was not created by codex (e.g. --output-last-message not honored by the installed version) or the temp directory lost write permissions.
Common situations: Codex version that doesn't support --output-last-message; sandbox prevented codex from writing; a buildEnvironment/CODEX_HOME mismatch redirecting output; temp dir on a no-write filesystem.
Related errors
- Codex review timed out
- Codex review failed${detail ? `: ${detail}` : ''}
- Codex returned an empty final response
- git status failed: {stderr}
- Multiple ECC repo roots detected: ${uniqueRepoRoots.join(',
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/e90e7260846e5116.
Report an issue: GitHub.