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

  1. Confirm the installed Codex is exactly SUPPORTED_CODEX_VERSION (0.146.0), which honors --output-last-message.
  2. Check that os.tmpdir() is writable by the spawning process.
  3. Inspect the wrapped fs error message (ENOENT vs EACCES) to localize the cause.
  4. 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

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


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/e90e7260846e5116. Report an issue: GitHub.