affaan-m/ECC · error · Error
OpenAI transfer consent is required
Error message
OpenAI transfer consent is required
What it means
runReview() requires explicit consent before sending the packet to OpenAI's Codex CLI, because the review content leaves the local machine. If options.consent is falsy, this error is thrown. In the CLI this consent is granted via the --consent-to-openai flag; as a library call you must set consent: true in the options object.
Solutions
- Pass consent: true in the options object: runReview(prompt, { consent: true, hostProvider: 'anthropic', timeoutMs: 60000 })
- For CLI use, add the --consent-to-openai flag
- If consent should be dynamic, prompt the user for confirmation and set the flag based on their answer
- Only grant consent when the packet content is safe to send to a third-party service
Example fix
// before
runReview(packet, { hostProvider: 'anthropic', timeoutMs: 60000 });
// after
runReview(packet, { consent: true, hostProvider: 'anthropic', timeoutMs: 60000 }); Defensive patterns
Strategy: validation
Validate before calling
function hasConsent(options) {
return options != null && options.consent === true;
}
if (!hasConsent(opts)) throw new Error('set options.consent = true before external review'); Type guard
function isConsentedOptions(o) {
return typeof o === 'object' && o !== null && o.consent === true;
} Try / catch
try {
return runReview(prompt, options);
} catch (err) {
if (err.message === 'OpenAI transfer consent is required') {
console.error('Pass --consent-to-openai (CLI) or consent: true (library)');
process.exitCode = 2;
return null;
}
throw err;
} Prevention
- Always build options through parseArgs rather than hand-rolled objects
- Make consent an explicit, reviewed step in automation pipelines
- Never default consent to true silently
- Document that library callers must set consent: true themselves
When it happens
Trigger: runReview(prompt, { consent: false, ... }) or runReview(prompt, {}) — consent flag omitted; CLI invoked without --consent-to-openai (though parseArgs normally catches that first, direct library callers bypass parseArgs).
Common situations: Programmatic callers constructing the options object by hand and forgetting consent: true; scripts composing runReview without the argument parser; teams intentionally requiring a user-visible opt-in before external transfer.
Understand the failure class
Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.
Related errors
- review packet exceeds
- review packet is empty
- -32602
- a claim token is required
- a confirmed nonempty coordinate is required
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/c93df39ede029a2c.
Report an issue: GitHub.
Appendix: source
Thrown at skills/council-multi-model/scripts/review-with-codex.js:186
return versionMatch[1];
}
function buildEnvironment(sourceEnv = process.env) {
const allowed = [
'PATH', 'HOME', 'USERPROFILE', 'CODEX_HOME',
'TMPDIR', 'TMP', 'TEMP', 'SystemRoot', 'ComSpec', 'PATHEXT',
];
return Object.fromEntries(
allowed.filter((name) => sourceEnv[name]).map((name) => [name, sourceEnv[name]])
);
}
function runReview(prompt, options, dependencies = {}) {
if (!prompt.trim()) throw new Error('review packet is empty');
if (Buffer.byteLength(prompt, 'utf8') > MAX_PROMPT_BYTES) {
throw new Error(`review packet exceeds ${MAX_PROMPT_BYTES} bytes`);
}
if (!options.consent) throw new Error('OpenAI transfer consent is required');
if (options.timeoutMs < 10_000 || options.timeoutMs > MAX_TIMEOUT_MS) {
throw new Error('timeout is outside the 10-120 second safety range');
}
const spawn = dependencies.spawnSync || spawnSync;
const environment = buildEnvironment(dependencies.env || process.env);
const verifySupport = dependencies.verifyToollessSupport || verifyToollessSupport;
verifySupport({ spawnSync: spawn, env: environment });
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,View on GitHub (pinned to 8321021c54)