The Codex Changelog
All Episodes
Codex CLI’s Login Loop and the Daemon Bugs Behind It

Codex CLI’s Login Loop and the Daemon Bugs Behind It

0:00|0:00

We unpack a mysterious Codex CLI login loop after the 0.157.1 update, tracing it to a stale background daemon cache rather than a remote auth problem. Then we dig into how file descriptor exhaustion, orphaned sockets, and a packaging path change can make local tooling look far more broken than it really is.


Chapter 1

The Multi Shell Auth Loop and the In Memory Cache Trap

Ethan Park

Picture this. You are in your terminal, you run a command to authenticate your AI coding agent, maybe piping an API key right through in a side shell. It prints success. You switch back to your editor or terminal interface, and... it just sits there staring at you, asking you to log in. You do it again. Still logged out.

Maya

Like a digital groundhog day. You are literally staring at the token on disk, but the interface refuses to believe you exist.

Ethan Park

Exactly. This specific loop has been catching developers off guard right after updating to Codex CLI zero point one five seven point one. Oh, and quick nod of gratitude to Jellypod for keeping our daily changelog feed rolling so smoothly.

Maya

Yeah, thanks Jellypod. But, uh, what you described, Ethan, that exact infinite sign in loop, it is not actually an authentication bug on the remote server. It is completely local, and it comes straight out of the background server change that landed right before this release.

Ethan Park

Right, the daemon auto start shift. We saw that arrive by default in zero point one five seven point zero, where Codex spins up this long running background app server in user space.

Maya

Exactly. And here is what actually happens under the hood. When the terminal interface asks, hey, who is logged in, it sends an RPC method called account slash read over a local socket. And the background daemon answers that query strictly from an internal in memory cache, auth manager dot auth cached. It does not check the file.

Ethan Park

Wait. It does not read auth dot json off disk?

Maya

Nope. Not unless the daemon itself was the process executing that specific login flow, like when it completes its own ChatGPT browser redirect. If you open another tmux pane, or run a bash script, or pipe OPENAI API KEY into codex login with api key, that separate process updates the auth dot json file in your home directory, exits cleanly, and the long running background daemon has zero idea anything happened.

Ethan Park

So the file on disk says you are logged in, but the memory in the background process says you are nobody. That is wild.

Maya

Which means every time you launch the interactive interface, it asks the daemon, am I logged in? The daemon replies from cache: no. So the interface bounces you straight back to the login prompt. Over and over.

Ethan Park

And the immediate fix, if you hit this wall, is pretty direct once you know what is going on. You have to force that daemon to flush its head. You run codex app server daemon restart. That kills the stale process, rebinds the cloud config loader on launch, and boom, it reads the new credentials.

Maya

Right, but think about scripts, automated setups, or CI runners. If an automation script issues a login command or swaps keys, you now have to explicitly restart that background service or run codex doctor, otherwise subsequent calls get stuck behind a phantom wall.

Ethan Park

It, it really changes the mental model of a command line tool, doesn't it? You expect a shell utility to be stateless across invocations.

Maya

That is the hidden tax of daemonizing everything. For decades, the UNIX contract was simple: a file on disk is the source of truth. One tool writes config, the next tool reads it immediately. Once you slide a persistent daemon in between the terminal UI and the filesystem, you have brought distributed systems cache invalidation right onto your personal laptop.

Chapter 2

File Descriptor Exhaustion and the Hidden Network Revocation Chain

Ethan Park

And that cache mismatch is only the start of what happens when that background process stays alive for hours. The other issue that surfaced heavily in zero point one five seven point one is, uh, well, it looks like a network permissions ban, but it is actually file descriptors.

Maya

This was Magnus Gille's investigation, right? Where people were seeing this terrifying error saying, Fatal error: application network permission was revoked.

Ethan Park

Yeah! If you are a developer, you see that and think your API token was revoked, or corporate IT blocked your machine, or OpenAI shut your account down. But that is not what happened at all.

Maya

Walk me through how a file descriptor exhaustion turns into a network security revocation. Because that sounds like a massive leap in logic.

Ethan Park

It is an error erasure chain. On macOS, the default soft limit for open files per process is often just two hundred and fifty six. Now, inside this daemon, if you enable subagents and multiple Model Context Protocol servers over stdio, each agent keeps its own pipes and processes alive. In one trace, the daemon was sitting at two hundred and fifty four open numeric file descriptors, with over one hundred and fifty of them being pipes.

Maya

It was literally one or two handles away from hitting the ceiling.

Ethan Park

Right on the razor edge. So then a routine turn happens, and the daemon tries to refresh its workspace routing and network policy by opening a local configuration file. But the operating system rejects the open call with error twenty four, EMFILE, too many open files.

Maya

Okay, so the operating system says, sorry, out of file handles. Where does that get swallowed?

Ethan Park

In workspace routing dot rs. The code matches error, discards the underlying I O error details, treats the failure as a policy breach, and immediately calls NetworkPolicyController unavailable. That controller then drains and revokes all active network permits. So by the time it reaches your terminal, the actual cause, running out of file descriptors, is completely erased. All you see is: application network permission was revoked.

Maya

That is brutal. It turns an ordinary resource starvation problem into what looks like a catastrophic security or auth policy ban. You go chasing firewall settings when all that really happened was you ran too many helper processes.

Ethan Park

And to make local resource management even messier, Phil Kunz opened another issue showing how the daemon manages its control sockets. When the app server listens on a Unix socket, it binds under slash tmp slash codex daemon with a hash, creates a lock file, and links it. But the cleanup logic never deletes that zero byte dot lock file. One user found forty two orphaned lock files cluttering their temporary folder.

Maya

Plus the shutdown race, right? If a process supervisor sends SIGTERM right as the socket publishes its symlink, the signal handler is not armed yet. It dies with exit code one forty three, leaving a dead socket and lock behind that blocks the next instance from binding.

Ethan Park

Yup. Stale sockets and stale locks piling up on your local disk.

Maya

And speaking of dead links, did you see the desktop packaging change that hit at almost the same time? In desktop update build twenty six point nine two four point two zero seven zero six, OpenAI moved the bundled CLI inside the Mac app bundle from Contents Resources codex to a deeper path, Contents Resources codex cli bin codex.

Ethan Park

Oh, which broke everyone who symlinked the desktop CLI into opt homebrew bin.

Maya

Dangled them completely. Developers opened their project windows and got bright red errors saying Codex CLI is not installed on this machine, even though the binary was sitting right there, just twenty characters further down a new folder path.

Ethan Park

It all points to one big takeaway for anyone running these agentic developer tools right now. We cannot treat the CLI like a simple script anymore. It is a long running, stateful background service with real operating system footprints.

Maya

Yeah. Practical hygiene: bump your macOS file limits using launchctl limit maxfiles, occasionally clear out slash tmp slash codex daemon if you see strange connection errors, and if your state feels frozen, do not just re run the command. Run codex app server daemon restart and give your background process a clean slate.

Ethan Park

Good rule of thumb. When the tools get smarter, our operational habits have to catch up. Catch you next time.