affaan-m/ECC · error · Error

Codex returned an empty final response

Error message

Codex returned an empty final response

What it means

The output file was read successfully but its trimmed contents are empty. The library requires a non-empty final response from Codex to include in the multi-model council, so an empty string is rejected with this error rather than returning blank review text.

Solutions

  1. Re-run the review — a transient empty model response often succeeds on retry.
  2. Shrink or restructure the review packet; overly large prompts can yield no output.
  3. Verify the Codex CLI version writes its final response to the expected output file (test with a trivial prompt).
  4. Check whether the response appears on stdout instead — a version-behavior change is a common cause.
  5. If refusals are the cause, adjust the prompt to comply with content policy.

Example fix

// before
await runReview({ prompt: 500KBpacket, ... }); // empty response
// after
await runReview({ prompt: compactPacket(sections), ... }); // smaller prompt, non-empty response
Defensive patterns

Strategy: retry

Try / catch

async function reviewWithRetry(opts, attempts = 2) {
  try {
    return runReview(opts);
  } catch (e) {
    if (e.message === 'Codex returned an empty final response' && attempts > 1) {
      return reviewWithRetry(opts, attempts - 1);
    }
    throw e;
  }
}

Prevention

When it happens

Trigger: Codex exits 0 and writes outputFile, but the file contains only whitespace (or nothing) — the model produced no final message, output was redirected elsewhere, or stdout vs file confusion left the file blank.

Common situations: Codex hit a content refusal producing no final text; CLI version writing the response to stdout instead of the file; prompt so large the model returned nothing; a transient model failure reported as silent success.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/d721c3c95f9d18b6. Report an issue: GitHub.

Appendix: source

Thrown at skills/council-multi-model/scripts/review-with-codex.js:228

    });

    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');
  stdin.on('data', (chunk) => {
    if (promptOverflow) return;

View on GitHub (pinned to 8321021c54)