Fifty-nine hours of a Codex that would not start
From the morning of 25 September until we noticed on the afternoon of
the 27th, ovm install codex gave you the latest Codex in a
form its terminal UI could not start — on macOS until OVM 0.1.10 that
evening, and on Linux, which we missed, until 0.1.11 the next morning.
Our verification gate looked at both affected versions and admitted
them. This is what happened, with the clock on it, and what we changed
so the gate says no next time.
If you installed Codex 0.157.0 or 0.157.1 through OVM and got
this CLI has no complete local package, we are sorry. The
break was ours, not Codex's, and it took us two and a half days to
notice something our own pipeline should have caught within hours.
OVM 0.1.11 fixes new installs and repairs existing ones, on macOS
and on Linux; ovm self update then
ovm install codex is the whole recovery. Until you
update, codex --no-daemon works.
Linux was broken too, and our first fix missed it. An earlier version of this post said only that Linux "still installs the bare binary", which read as if Linux were fine. It was not, and Linux users stayed broken for eight and a half hours longer than macOS users. Section 5 says how that happened.
1What broke
From 0.157, the Codex terminal UI runs on a background app server —
a daemon it starts on first launch. It will only start that server
from a complete package: the binary, a manifest
(codex-package.json), a bundled rg, and a
codex-resources/ folder. OpenAI publishes that package as
its own release asset, codex-package-<target>.tar.gz,
alongside the bare binary it has always shipped.
OVM 0.1.9 installs the bare binary. It always has, and until 0.156.1
that was the whole program. On 0.157 the bare binary reports its
version, runs codex exec, and does everything except the
one thing most people launch it for: the interactive UI fails at
startup with
this CLI has no complete local package; install a packaged Codex CLI or use the standalone installer … rerun with --no-daemon
The message is Codex's own. It does not say that the installer at fault was OVM, and there was nothing in our output to say it either.
One qualification. Codex installs its daemon into your Codex home the first time a complete package starts, and any Codex after that finds it there. If another install on the machine — the desktop app, an npm or standalone Codex — had already done that, the bare OVM install started fine. The break was for people whose Codex came from OVM alone, which is what OVM is for.
2Timeline
All times UTC.
- Codex rust-v0.157.0 is published as a stable release. From this moment
ovm install codexresolves to a version whose UI cannot start from what OVM installs. - Our gate withholds 0.157.0 from the registry — not because it found anything, but because nothing had qualified the version yet.
- The gate admits 0.157.0: every state-migration and recovery contract passed, and the launch check reported ready.
- Codex rust-v0.157.1 is published.
- The gate admits 0.157.1 with degraded evidence — one of four lanes failed verification and was not credited — and clears it fully at 03:18.
- We hit the error ourselves, launching Codex through OVM on a laptop. Nobody had reported it; we found it by using it.
- Fix on
main: on macOS, when a release publishes the package, OVM installs the package. - Repair on
main: an existing bare 0.157 install is reinstalled with the package on the nextovm install codex. - Gate fix on
main: the launch check no longer calls a UI that draws and dies "ready"; the daemon-package error is a recognised failure. - OVM 0.1.10 is published as Latest — the macOS fix. Linux still installs the bare binary.
- Following up an open question in this post, we reproduce the same startup error with a bare Codex 0.157.1 on a clean Ubuntu 24.04 machine. Linux users are broken too.
- The Linux fix passes end to end on Ubuntu: install, repair of a bare tree, no reinstall loop. Review caught a second bug on the way — the Linux package keeps its sandbox helper somewhere our final install check did not look, so every Linux install would have been refused.
- OVM 0.1.11 is published as Latest — the Linux fix.
59 hours from the first broken version to detection.
Six minutes from detection to a fix on main, which says
the fix was easy and the finding was the whole problem.
Eight and a half hours from there to a release, most of it the gates a
stable release goes through — CI, a rehearsal cut, the private canary,
the public rebuild with signing, notarisation and attestation — plus
two of our own release rules that had never met a hotfix branch.
For Linux the whole span, from the first broken version to 0.1.11,
was 77 hours.
3Why the gate said yes
Every Codex release goes through a verification gate before the registry vouches for it: state-database downgrade and recovery contracts on both platforms, a launch of the interactive UI in a real terminal, and a signature assessment of the binary. A version that fails is withheld and pages us. This one passed, eight times.
The launch check decided ready when it had seen two terminal control sequences — the ones that turn on bracketed paste and focus reporting — and the process was still alive half a second later. That heuristic was written for the failure it had seen: a UI that never comes up, or exits at once. The bare 0.157 binary emits both sequences as its very first output, then goes looking for its package, and fails. By then the check had already recorded a pass.
The gate was measuring the terminal being prepared, and calling that the program working. It is the same shape as the npm that answered from the past: a signal that looks like success, read at the same confidence as success.
The other checks could not have caught it either. The state contracts
test the database, which this bug does not touch; codex exec
does not need the daemon. And the credential-less probe we run on
GitHub-hosted runners — the lane closest to a new user's machine,
because it installs the released OVM into an empty home — only asked
codex --version, which a bare binary answers perfectly.
That probe did fail on macOS for 0.157.1, but for an unrelated reason:
the runner's shared anonymous GitHub API quota was exhausted and the
download got a 403. Had it downloaded, it would have passed.
4What changed
-
OVM 0.1.10 installs the complete package on macOS
whenever a release publishes one: size-checked, SHA-256 checked
against the digest GitHub publishes for the asset, extracted with
the same hardened extractor as every other download, manifest and
code signature verified. Older releases install exactly as before.
If the package download fails, OVM falls back to the bare binary
and tells you about
--no-daemon. -
Existing installs are repaired. A 0.157 tree
installed without the package is reinstalled by the next
ovm install codex <version>, the same way an install missing a sidecar already was. - The launch check no longer trusts the first two bytes. Ready now needs a rendered prompt and a longer stable window, and the daemon-package error is recognised as the fatal error it is. Replayed against what the bare 0.157.1 binary prints, the check now fails, and a failing launch on the latest run withholds the version even if an earlier run had passed.
- The hosted probe now starts the UI. Signed out, a working Codex stays up on its sign-in screen; one missing its package exits within a second. The probe runs it for ten seconds under a real terminal and fails the version on an early exit or the package error, and it now downloads with a token instead of the shared anonymous quota. This lane needs no credentials and runs within minutes of an upstream release, so it is the one that would have caught 0.157 first.
-
OVM 0.1.11 does the same on Linux: the package is
installed and a bare tree is repaired. The Linux package keeps its
sandbox helper (
bwrap) incodex-resources/besidebin/, where our older layout had it insidebin/; OVM now looks for each helper where the package puts it. - 0.1.10 and 0.1.11 are patches cut from 0.1.9 with these fixes only. Everything else that has landed since ships as 0.2.0, on its own schedule.
5How we missed Linux
We found the break on a Mac, fixed it on macOS, and deferred Linux: its package puts the sandbox helper somewhere else, and we wanted to check that before switching. That was a reasonable thing to check. What we did not do was ask the prior question — whether Linux users were broken in the meantime — and the post said "Linux still installs the bare binary" as if that were a neutral fact. A bare binary was the whole bug. Every check we had on Linux was the same kind as the ones that missed it on macOS, so nothing was going to tell us.
It surfaced the next morning while chasing a different open question. Checking before switching turned out to matter as well: the first Linux fix would have been refused by our own post-install check, which looked for the sandbox helper in the old place. Code review caught that, and a real Ubuntu machine confirmed it, before anything shipped. The rule we are keeping: when a fix is scoped to one platform, the others get checked for the same break the same day, not deferred along with the fix.
6What we are still doing
- Catching this class earlier. A launch that comes up is not a launch that works. We are looking at sending one keystroke through the UI and requiring a render, and at diffing a version's first second of output against the previous version's, so a new fatal line is a review trigger rather than noise.
7References
- openai/codex — rust-v0.157.0 · the first release whose UI requires the complete package
- ovm-sh/ovm-oss — releases · OVM 0.1.10 (macOS) and 0.1.11 (Linux)
- The npm that answered from the past · the earlier post on signals that look like answers