New models cache breaks older clients sharing CODEX_HOME

Open 💬 1 comment Opened Aug 18, 2026 by joshmouch

What happens

Codex 0.148 writes models_cache.json entries with canonical model_messages.instructions_template but without the deprecated top-level base_instructions. An older Codex 0.146 process sharing the same CODEX_HOME deserializes the complete model array before checking client_version, so it logs:

failed to load models cache: missing field `base_instructions`

It then falls back to a remote fetch, so functionality continues, but the warning recurs whenever the newer process refreshes the shared cache.

Source gap

ModelsResponse already uses both serialize_model_infos_with_legacy_base and deserialize_model_infos_with_legacy_base. ModelsCacheEntry.models uses only the deserializer, so the compatibility guarantee is lost specifically when persisting the file cache.

Proposed fix

Commit https://github.com/joshmouch/codex/commit/59449eb735 adds the existing legacy serializer to ModelsCacheEntry.models and a raw persisted-JSON regression.

Verification:

  • cargo fmt -- --check
  • cargo test -p codex-models-manager (49 passed)
  • cargo clippy -p codex-models-manager --all-targets --all-features -- -D warnings

I can open the PR if a maintainer invites it under the repository contribution policy.

View original on GitHub ↗

1 Comment

tsuvic · 9 days ago

Corroborating both the source gap and the in-the-wild file state on macOS.

Source (main @67ed4e7): ModelsCacheEntry.models carries only deserialize_with = deserialize_model_infos_with_legacy_base (codex-rs/models-manager/src/cache.rs:76), while ModelsResponse has both serialize and deserialize (codex-rs/protocol/src/openai_models.rs:695–696) — the persisted cache drops exactly the compatibility the wire format keeps, as described.

In situ: on a machine where standalone CLI 0.147.0 and the desktop-bundled 0.148 share ~/.codex, the current models_cache.json (refreshed 2026-08-19T01:28Z, client_version: "0.148.0") contains 7 instructions_template entries and zero base_instructions fields — precisely the shape that fails legacy deserialization for the older client on the same CODEX_HOME.

+1 on the proposed fix (adding the existing legacy serializer to ModelsCacheEntry.models); it matches the in-tree precedent.