Rate‑limit 429 causes Codex CLI abort / raw‑mode crash
Environment
- CLI version:
codex --version→ v0.1.04161006 - Model: o3
- OS: macOS Sequoia 15.4 (Apple Silicon)
- Node.js: v23.10.0
- Org ID:
org‑REDACTED
Steps to reproduce
- Run
codex --model o3 edit(interactive mode) - Submit a large
apply_patchblock (~29 k tokens) - CLI retries once, then receives 429 → Ink raw‑mode crash
Observed error
[Error]: Rate limit reached for o3 in organization org‑REDACTED on tokens per min (TPM): Limit 30000, Used 23669, Requested 29142. Please try again in 45.622s. Visit https://platform.openai.com/account/rate-limits to learn more.
at e.a [as iterator] (file:///opt/homebrew/lib/node_modules/@openai/codex/dist/cli.js:443:1514)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async I0.run (file:///opt/homebrew/lib/node_modules/@openai/codex/dist/cli.js:460:2356) {
status: undefined,
headers: undefined,
request_id: undefined,
error: {
type: 'tokens',
code: 'rate_limit_exceeded',
message: 'Rate limit reached for o3 in organization org-REDACTED on tokens per min (TPM): Limit 30000, Used 23669, Requested 29142. Please try again in 45.622s. Visit https://platform.openai.com/account/rate-limits to learn more.',
param: null
},
code: 'rate_limit_exceeded',
param: null,
type: 'tokens'
}
The session aborts; partial patch is lost.
Expected behavior
- CLI should automatically back‑off or chunk large patches after a 429
- No fatal crash when Ink UI fails to enter raw mode
Possible improvements
- Document
OPENAI_MAX_RETRIES/OPENAI_MS_BETWEEN_RETRIES - Auto‑chunk patches > 30 k tokens
- Default to
--no-uion automatic retries to avoid raw‑mode issues
18 Comments
Submitted https://github.com/openai/codex/pull/153, could you build from source and verify that this fixed your issue?
Adding this in case it might be helpful in any way, on version 0.1.2504161551:
!Image
Follow‑up: CLI still exits after second 429
PR #153 fixed the Ink raw‑mode crash (thanks!), but the CLI still aborts
entirely once it receives a second 429 in the same request cycle. This forces
the user back to the shell and loses context.
Steps to reproduce
codex --model o3 edit(interactive or--no-ui)process exits (status 1).
Expected
OPENAI_MAX_RETRIES/OPENAI_MS_BETWEEN_RETRIESby default, or prompt the user rather than exiting.
TPM bucket.
Environment is the same as in #157 (macOS 15.4, Node 23.10.0, CLI 0.1.2504161510).
FYI:
Additional stack (first frames):
file:///Users/west/Code/codex‑cli-fix/codex‑cli/dist/cli.js:445:…
at e.a [as iterator] (.../cli.js:443:1514)
at async I0.run (.../cli.js:460:2356)
(full minified trace available if needed)
A NOTE FOR CLARIFICATION
I apologize for this part of the response "PR https://github.com/openai/codex/pull/153 fixed the Ink raw‑mode crash (thanks!)" that has nothing to do with the issue. o3 was helping me troubleshoot and hallucinated that that was part of the bug.
I only caught what was going on after re-checking the logs.
From o3 attempting to set the record straight :
Clarification (16 Apr 2025)
My earlier description reused the phrase “Ink raw‑mode crash,” but that
specific error line is not present in my current logs.
What I’m seeing now is:
apply_patch(> 30 k tokens total).rate_limit_reached(429), waits, retries once.shell, so the patch is lost.
No
Raw mode is not supported...line appears, and the terminal is not in abroken state; the program just quits after the second 429.
Request: have the CLI keep backing‑off (or auto‑chunk the patch) instead of
quitting after one retry.
Same here on
o4-mini. In most cases I can't go to any meaningful with any request most of them take more then rate limit is so it's hard to do anything.Same here, we had announcement of gpt-4.1 and Codex CLI, but seems it's not usable for personal use as it exceed token limits. I asked for fix unit tests where I do a special error to see how it handles it, and well..
Request too large for gpt-4.1 in organization org-gZ... on tokens per min (TPM): Limit 30000, Requested 81483Also seeing this with
o4-miniandcodexv0.1.2504161551. Codex should just wait the time given by the server and retry:WIP pull request in:
https://github.com/openai/codex/pull/176
Related fix in https://github.com/openai/codex/pull/266, should work if you build and run from main.
Latest release still experiences the issue.
Just wanted to confirm I'm also affected by this rate limit handling issue with gpt-4.1. The CLI stopping instead of waiting is the main pain point.
Echoing the previous comments, the ideal solution would be for the CLI to automatically parse the "Please try again in X.Xs" time from the 429 error message, wait that duration, and then retry the request. Having this built-in would make codex cli much more robust. Hope this fix can be prioritized.
Built from main.Problem still exists
e [Error]: Rate limit reached for o4-mini in organization org-s1NXN1xEWxsFLjqXYxQoz1Mi on tokens per min (TPM): Limit 200000, Used 141821, Requested 58778. Please try again in 179ms
I've created a PR with a fix that's been working for me
https://github.com/openai/codex/pull/357
still experiencing this on latest build
Heap‑out‑of‑memory while loading large patch (blocks 429‑retry testing)
0.1.250419(npm)v23.10.0_1(Apple M4 Max, macOS 15.4)Oh and btw - rate limit bug is still happening too:
codex‑cli 0.1.250419 (npm)
Node v23.10.0_1 (Apple M4 Max, macOS 15.4)
file:///opt/homebrew/lib/node_modules/@openai/codex/dist/cli.js:449
,"\r"]);gg.NEWLINE_REGEXP=/\r\n|[\n\r]/g;function uwe(e,t){for(let a=t??0;a<e.length;a++){if(e[a]===10)return{preceding:a,index:a+1,carriage:!1};if(e[a]===13)return{preceding:a,index:a+1,carriage:!0}}return null}function pae(e){for(let n=0;n<e.length-1;n++){if(e[n]===10&&e[n+1]===10||e[n]===13&&e[n+1]===13)return n+2;if(e[n]===13&&e[n+1]===10&&n+3<e.length&&e[n+2]===13&&e[n+3]===10)return n+4}return-1}g();function IO(e){if(e[Symbol.asyncIterator])return e;let t=e.getReader();return{async next(){try{let r=await t.read();return r?.done&&t.releaseLock(),r}catch(r){throw t.releaseLock(),r}},async return(){let r=t.cancel();return t.releaseLock(),await r,{done:!0,value:void 0}},[Symbol.asyncIterator](){return this}}}var id=class e{constructor(t,r){this.iterator=t,this.controller=r}static fromSSEResponse(t,r){let n=!1;async function*a(){if(n)throw new Error("Cannot iterate over a consumed stream, use.tee()to split the stream.");n=!0;let i=!1;try{for await(let s of dwe(t,r))if(!i){if(s.data.startsWith("[DONE]")){i=!0;continue}if(s.event===null||s.event.startsWith("response.")||s.event.startsWith("transcript.")){let c;try{c=JSON.parse(s.data)}catch(d){throw console.error("Could not parse message into JSON:",s.data),console.error("From chunk:",s.raw),d}if(c&&c.error)throw new mi(void 0,c.error,void 0,wO(t.headers));yield c}else{let c;try{c=JSON.parse(s.data)}catch(d){throw console.error("Could not parse message into JSON:",s.data),console.error("From chunk:",s.raw),d}if(s.event=="error")throw new mi(void 0,c.error,c.message,void 0);yield{event:s.event,data:c}}}i=!0}catch(s){if(s instanceof Error&&s.name==="AbortError")return;throw s}finally{i||r.abort()}}return new e(a,r)}static fromReadableStream(t,r){let n=!1;async function*a(){let s=new gg,c=IO(t);for await(let d of c)for(let f of s.decode(d))yield f;for(let d of s.flush())yield d}async function*i(){if(n)throw new Error("Cannot iterate over a consumed stream, use.tee()to split the stream.");n=!0;let s=!1;try{for await(let c of a())s||c&&(yield JSON.parse(c));s=!0}catch(c){if(c instanceof Error&&c.name==="AbortError")return;throw c}finally{s||r.abort()}}return new e(i,r)}[Symbol.asyncIterator](){return this.iterator()}tee(){let t=[],r=[],n=this.iterator(),a=i=>({next:()=>{if(i.length===0){let s=n.next();t.push(s),r.push(s)}return i.shift()}});return[new e(()=>a(t),this.controller),new e(()=>a(r),this.controller)]}toReadableStream(){let t=this,r,n=new TextEncoder;return new mN({async start(){r=t[Symbol.asyncIterator]()},async pull(a){try{let{value:i,done:s}=await r.next();if(s)return a.close();let c=n.encode(JSON.stringify(i)+e [Error]: Rate limit reached for o3 in organization org-xxx on tokens per min (TPM): Limit 450000, Used 389392, Requested 70032. Please try again in 1.256s. Visit https://platform.openai.com/account/rate-limits to learn more.
at e.a [as iterator] (file:///opt/homebrew/lib/node_modules/@openai/codex/dist/cli.js:449:1514)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async T0.run (file:///opt/homebrew/lib/node_modules/@openai/codex/dist/cli.js:466:2933) {
status: undefined,
headers: undefined,
request_id: undefined,
error: {
type: 'tokens',
code: 'rate_limit_exceeded',
message: 'Rate limit reached for o3 in organization org-xxx on tokens per min (TPM): Limit 450000, Used 389392, Requested 70032. Please try again in 1.256s. Visit https://platform.openai.com/account/rate-limits to learn more.',
param: null
},
code: 'rate_limit_exceeded',
param: null,
type: 'tokens'
}
Node.js v23.10.0
This was now fixed a while ago, and going to close this. Please ensure that you are running the latest version here: https://github.com/openai/codex/blob/main/CHANGELOG.md#012504251709
You should see