Codex Desktop hides local history for custom Azure model provider after restart (e.g. corporate API key)

Open 💬 6 comments Opened Apr 29, 2026 by uberkinder
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

26.422.71525

What subscription do you have?

personal + corporate AzureOpenAI API key

What platform is your computer?

26.0 (25A8353)

What issue are you seeing?

  • Optional provider filter; when set, only sessions recorded under these
  • providers are returned. When present but empty, includes all providers.

*/
modelProviders?: Array<string> | null


Local testing showed:

- `thread/list` with `modelProviders: []` returned both `openai` and `azure` threads.
- `thread/list` with `modelProviders: null` could behave like a current-provider filter.
- The Desktop UI bundle contains `thread/list` calls with `modelProviders:null`.

This suggests the Desktop UI may be listing recent threads using provider filter semantics that exclude custom providers after restart, or it may be applying a UI-side provider filter that does not include custom providers.

## Additional Observations

`thread/list` without a `cwd` filter and with `modelProviders: []` returned mixed providers, including both:

```text
openai | vscode | /Users/uberkinder/projects/bp/Hercules
azure  | vscode | /Users/uberkinder/projects/bp/Hercules
azure  | vscode | /Users/uberkinder/projects/bp/Hercules
azure  | vscode | /Users/uberkinder/projects/bp/Hercules

thread/list with a cwd filter for Hercules and modelProviders: [] also returned both openai and azure threads in that repo.

This further supports that the underlying app-server can return the data needed by the UI.

Failed Workarounds

1. Duplicating Provider Definition Into Repo Config

Duplicating [model_providers.azure] into the repo-local .codex/config.toml did not fix Desktop history.

CLI still worked and reported:

provider: azure

But the Desktop GUI still did not show corporate/Azure chats after restart.

2. Trying To Override Built-In openai Provider

Attempting to configure built-in openai to point at Azure did not work. Codex still sent requests to:

https://api.openai.com/v1/responses

This is not a viable workaround.

3. Patching app.asar

Two local experiments were attempted only to test the provider-filter hypothesis. Both are not viable and should not be used as a workaround.

First attempt:

  • Extracted app.asar.
  • Replaced modelProviders:null in JS.
  • Repacked app.asar.
  • Result: Codex Desktop crashed at startup with EXC_BREAKPOINT (SIGTRAP).
  • Likely cause: repacking lost original app.asar.unpacked metadata for native modules.

Second attempt:

  • Performed an in-place byte-preserving edit:

``js
modelProviders:null
``

to:

``js
modelProviders:([])
``

  • Same byte length.
  • No extract/repack.
  • Updated affected asar integrity hashes in the header.
  • Tested successfully on a /tmp copy with @electron/asar list.
  • Result on the real installed app: Codex Desktop still crashed at startup with EXC_BREAKPOINT (SIGTRAP).
  • Likely cause: the installed app cannot tolerate mutation of Resources/app.asar, probably due to macOS/Electron code signing or resource seal validation.

Relevant crash reports:

/Users/uberkinder/Library/Logs/DiagnosticReports/Codex-2026-04-29-143709.ips
/Users/uberkinder/Library/Logs/DiagnosticReports/Codex-2026-04-29-143726.ips

Resources/app.asar is listed in:

/Applications/Codex.app/Contents/_CodeSignature/CodeResources

So mutating the installed app bundle is not a practical workaround.

Impact

This makes corporate/custom-provider usage unsafe and confusing:

  • Work is not lost, but appears lost in the GUI.
  • Users cannot reliably reopen or continue corporate Azure chats from Desktop history.
  • Personal/default OpenAI history works, making the issue look provider-specific.
  • The intended setup of “corporate provider for one repo, personal provider elsewhere” becomes hard to use in Desktop.
  • Users may incorrectly assume their corporate chat history was deleted.

Requested Fix

Please make Codex Desktop recent/history views include custom provider threads correctly.

Specifically:

  1. Ensure thread/list calls intended to include all local threads use the correct provider filter semantics.
  2. Treat modelProviders: [] as “all providers” consistently, per the generated app-server protocol.
  3. Ensure custom providers such as azure are visible in recent chat history after app restart.
  4. Ensure opening/resuming a custom-provider thread renders existing turns instead of a blank UI.
  5. Add regression coverage for local custom providers with:
  • source = "vscode"
  • model_provider != "openai"
  • repo-scoped config selecting a custom provider
  • persisted local rollout JSONL history

Security Notes

  • No API key is included in this report.
  • The Azure endpoint is redacted.
  • Corporate chat content examples are limited to short thread titles/previews.

What steps can reproduce the bug?

Reproduction

  1. Configure a custom model provider named azure in ~/.codex/config.toml.
  2. Configure one repo with local .codex/config.toml selecting:

``toml
model_provider = "azure"
``

  1. Open Codex Desktop in that repo.
  2. Start one or more chats and verify that turns complete successfully through the Azure provider.
  3. Restart Codex Desktop.
  4. Check recent chat history.
  5. Observe that Azure-provider chats are missing or fail to open correctly, while default openai chats remain visible.

What is the expected behavior?

Expected Behavior

  1. Threads created in the Hercules repo with model_provider = "azure" should appear in Codex Desktop recent chat history.
  2. After restarting Codex Desktop, those Azure threads should still appear.
  3. Opening an Azure thread should render the existing conversation turns, same as model_provider = "openai" threads.
  4. Personal/default OpenAI threads from other repositories should continue to appear and open normally.

Actual Behavior

  1. Azure/provider-specific chats are created and saved successfully.
  2. They may appear temporarily in the Desktop GUI.
  3. After restarting Codex Desktop, Azure chats disappear from GUI history or open to a blank screen.
  4. Non-Azure/default OpenAI chats still appear and open normally.
  5. The missing Azure chats are not deleted and are not archived.

Additional information

019dd592-b080-7fc1-85d6-bb788ea20b45 | azure | vscode | /Users/uberkinder/projects/bp/Hercules | "ты можешь посмотреть пост..."
019dd59e-26bc-79d1-9c6b-209fc88805e6 | azure | vscode | /Users/uberkinder/projects/bp/Hercules | "открой в линеар кейс с Photon"
019dd399-904a-72a3-adcc-720754426b9f | azure | vscode | /Users/uberkinder/projects/bp/Hercules | "можешь в тимс ходить?"

These rows are present in:

/Users/uberkinder/.codex/state_5.sqlite

Their rollout JSONL files also exist under:

/Users/uberkinder/.codex/sessions/2026/04/29/

Evidence: Local App-Server Can Read The Threads

Using the local Codex app-server WebSocket API, both thread/list and thread/read can see/read the Azure threads.

Example thread/read for:

019dd592-b080-7fc1-85d6-bb788ea20b45

Returned:

{
  "id": "019dd592-b080-7fc1-85d6-bb788ea20b45",
  "modelProvider": "azure",
  "cwd": "/Users/uberkinder/projects/bp/Hercules",
  "source": "vscode",
  "turns": 20,
  "preview": "ты можешь посмотреть пост который я в Viva Engage закинул"
}

This indicates that the backend/state layer can load the conversation and the data is not lost.

Evidence: Provider Filter Semantics May Be Involved

Generated app-server TypeScript protocol says:

/**
 * Optional provider filter; when set, only sessions recorded under these
 * providers are returned. When present but empty, includes all providers.
 */
modelProviders?: Array<string> | null

Local testing showed:

  • thread/list with modelProviders: [] returned both openai and azure threads.
  • thread/list with modelProviders: null could behave like a current-provider filter.
  • The Desktop UI bundle contains thread/list calls with modelProviders:null.

This suggests the Desktop UI may be listing recent threads using provider filter semantics that exclude custom providers after restart, or it may be applying a UI-side provider filter that does not include custom providers.

Additional Observations

thread/list without a cwd filter and with modelProviders: [] returned mixed providers, including both:

openai | vscode | /Users/uberkinder/projects/bp/Hercules
azure  | vscode | /Users/uberkinder/projects/bp/Hercules
azure  | vscode | /Users/uberkinder/projects/bp/Hercules
azure  | vscode | /Users/uberkinder/projects/bp/Hercules

thread/list with a cwd filter for Hercules and modelProviders: [] also returned both openai and azure threads in that repo.

This further supports that the underlying app-server can return the data needed by the UI.

Failed Workarounds

1. Duplicating Provider Definition Into Repo Config

Duplicating [model_providers.azure] into the repo-local .codex/config.toml did not fix Desktop history.

CLI still worked and reported:

provider: azure

But the Desktop GUI still did not show corporate/Azure chats after restart.

2. Trying To Override Built-In openai Provider

Attempting to configure built-in openai to point at Azure did not work. Codex still sent requests to:

https://api.openai.com/v1/responses

This is not a viable workaround.

3. Patching app.asar

Two local experiments were attempted only to test the provider-filter hypothesis. Both are not viable and should not be used as a workaround.

First attempt:

  • Extracted app.asar.
  • Replaced modelProviders:null in JS.
  • Repacked app.asar.
  • Result: Codex Desktop crashed at startup with EXC_BREAKPOINT (SIGTRAP).
  • Likely cause: repacking lost original app.asar.unpacked metadata for native modules.

Second attempt:

  • Performed an in-place byte-preserving edit:

``js
modelProviders:null
``

to:

``js
modelProviders:([])
``

  • Same byte length.
  • No extract/repack.
  • Updated affected asar integrity hashes in the header.
  • Tested successfully on a /tmp copy with @electron/asar list.
  • Result on the real installed app: Codex Desktop still crashed at startup with EXC_BREAKPOINT (SIGTRAP).
  • Likely cause: the installed app cannot tolerate mutation of Resources/app.asar, probably due to macOS/Electron code signing or resource seal validation.

Relevant crash reports:

/Users/uberkinder/Library/Logs/DiagnosticReports/Codex-2026-04-29-143709.ips
/Users/uberkinder/Library/Logs/DiagnosticReports/Codex-2026-04-29-143726.ips

Resources/app.asar is listed in:

/Applications/Codex.app/Contents/_CodeSignature/CodeResources

So mutating the installed app bundle is not a practical workaround.

Impact

This makes corporate/custom-provider usage unsafe and confusing:

  • Work is not lost, but appears lost in the GUI.
  • Users cannot reliably reopen or continue corporate Azure chats from Desktop history.
  • Personal/default OpenAI history works, making the issue look provider-specific.
  • The intended setup of “corporate provider for one repo, personal provider elsewhere” becomes hard to use in Desktop.
  • Users may incorrectly assume their corporate chat history was deleted.

View original on GitHub ↗

6 Comments

github-actions[bot] contributor · 2 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #19088
  • #20004
  • #19318

Powered by Codex Action

uberkinder · 2 months ago
Potential duplicates detected. Please review them and close your issue if it is a duplicate. Azure OAI provider chat threads disappearing in thread list #19088 Codex Desktop should preserve local history visibility and continuation across providers/accounts #20004 * codex resume --all still filters by the current model provider #19318 _Powered by Codex Action_

I reviewed the suggested duplicates.

#19088 is the closest match and appears to describe the same user-visible Azure Desktop history symptom.

However, this issue adds narrower evidence that this is not merely "resume across providers":

  • the affected threads were created with model_provider = "azure"
  • the repo-local config still selects model_provider = "azure"
  • the rows are not archived
  • rollout JSONL files still exist
  • local app-server thread/read can read the affected Azure threads
  • thread/list with modelProviders: [] returns them
  • Desktop GUI still hides them or opens a blank screen after restart

So the requested behavior is not to resume an Azure thread through OpenAI or migrate encrypted content across providers. The requested behavior is that Desktop history/listing should show and open persisted threads under their original provider, or at least not hide same-provider Azure threads when the backend can already read them.

This seems distinct from the "by design" cross-provider resume limitation discussed in #19318 / #15494, and closer to a Desktop/app-server discovery/filtering bug.

uberkinder · 2 months ago

Reproduced again with a fresh minimal case after filing this issue.

On 2026-04-29 I created a brand-new chat in the same Hercules repo with repo-local model_provider = "azure". The chat completed successfully and was persisted locally. Then I closed Codex Desktop, reopened it, and the new Azure chat disappeared from GUI history as well.

The corresponding local row still exists and is not archived:

id: 019dd8b9-06d8-7b31-b397-180b0a6e2c25
title: test. creating new chat, again with azure openai
model_provider: azure
source: vscode
archived: 0
created_local: 2026-04-29 15:11:37 Asia/Tashkent
updated_local: 2026-04-29 15:11:46 Asia/Tashkent
rollout_path: ~/.codex/sessions/2026/04/29/rollout-2026-04-29T15-11-37-019dd8b9-06d8-7b31-b397-180b0a6e2c25.jsonl
paulhshort · 2 months ago

Ya this hit me as well after shifting from Azure to chatgpt pro sub. At the time, codex itself was able to patch my session history to switch Azure to openai within each session and was able to get them to show up again(and was able to resume them). Would love to see them implement better handling for these scenarios.

joshrad-dev · 1 month ago

FYI @uberkinder, it is possible to patch the ASAR with the patch you mentioned, you just have to take a few extra steps. Codex figured it out for me, so you could also ask it to do this for you: 😆

  APP="/path/to/Codex.app"
  WORK="/tmp/codex-asar-patch"
  ASAR="$APP/Contents/Resources/app.asar"

  rm -rf "$WORK"
  mkdir -p "$WORK"

  cp "$ASAR" "$WORK/app.asar.original"
  npx @electron/asar extract "$ASAR" "$WORK/extract"

Patch the extracted files however needed. For this specific issue:

  grep -R "modelProviders:null" "$WORK/extract"

  perl -pi -e 's/modelProviders:null/modelProviders:[]/g' \
    $(grep -rl "modelProviders:null" "$WORK/extract")

Repack the ASAR:

  npx @electron/asar pack "$WORK/extract" "$ASAR"

Update Electron’s ASAR integrity hash. This must hash the ASAR header string, not the whole file:

  HASH=$(
    npx -p @electron/asar node -e '
      const asar = require("@electron/asar");
      const crypto = require("crypto");
      const raw = asar.getRawHeader(process.argv[1]);
      console.log(crypto.createHash("sha256").update(raw.headerString).digest("hex"));
    ' "$ASAR"
  )

  plutil -replace ElectronAsarIntegrity.Resources/app.asar.hash -string "$HASH" \
    "$APP/Contents/Info.plist"

If you are making a copy of the app and want it to coexist with the installed one, change only the main bundle
identifier:

  plutil -replace CFBundleIdentifier -string com.example.codex.patched \
    "$APP/Contents/Info.plist"

Do not rename CFBundleName, and do not rename the helper apps.

Clear quarantine and resign:

  xattr -cr "$APP"

  find "$APP/Contents/Resources/app.asar.unpacked" -type f -print0 |
  while IFS= read -r -d '' f; do
    if file "$f" | grep -q 'Mach-O'; then
      codesign --force --sign - --preserve-metadata=entitlements,flags "$f"
    fi
  done

  codesign --force --deep --sign - "$APP"
  codesign --verify --deep --strict --verbose=1 "$APP"
QiuYe-123 · 12 days ago

Adding another reproduction from Windows with custom OpenAI-compatible providers. This is not Azure-specific.

Environment

  • Platform: Windows / Codex Desktop from Microsoft Store style WindowsApps install
  • Installed package observed locally: OpenAI.Codex_26.623.19656.0_x64__2p2nqsd0c76g0
  • ~/.codex/version.json reports latest_version: 0.141.0
  • Provider setup: multiple custom OpenAI-compatible endpoints configured via [model_providers.*] in config.toml
  • No endpoint URLs, provider ids, or API keys are included here.

User-visible behavior

After switching model_provider between custom OpenAI-compatible providers, the Desktop sidebar and the list_threads tool only show threads for the current provider. Threads from the previous provider appear to be gone, but they are still on disk and can still be read if the thread id is known.

Local evidence

The local state DB still contains threads across multiple provider buckets. The exact provider ids are omitted, but a read-only query against ~/.codex/state_5.sqlite showed non-archived thread records split across several buckets, for example:

provider bucket 1: 453
provider bucket 2: 338
provider bucket 3: 169
provider bucket 4: 134
provider bucket 5: 118
provider bucket 6: 48
provider bucket 7: 28
provider bucket 8: 6

At the time, list_threads returned only the currently active provider bucket. However, a hidden non-current-provider thread could still be read directly by id through the app thread API, confirming the data is not deleted and the JSONL/session state is still usable.

session_index.jsonl also does not contain a provider/model field, so the provider-specific visibility appears to come from the app-server/thread-listing path rather than from the raw session index.

Root-cause hint

This matches the provider filter semantics already discussed above:

/**
 * Optional provider filter; when set, only sessions recorded under these
 * providers are returned. When present but empty, includes all providers.
 */
modelProviders?: Array<string> | null

In the installed Windows app.asar, there are 10 occurrences of modelProviders:null in thread-listing paths. The affected bundled files include:

.vite/build/main-CTMsc2Ik.js                         1
.vite/build/src-CoIhwwHr.js                          1
webview/assets/app-window-focus-signal-DcI8YM20.js   1
webview/assets/split-items-into-render-groups-*.js   3
webview/assets/thread-context-inputs-*.js            4

Relevant examples include calls for recent threads, archived threads, dynamic list_threads, thread-id resolution, background thread hydration, and subagent tree lookup. These call sites appear to request all local threads, but pass modelProviders:null; per the generated protocol, the all-provider value should be an empty array (modelProviders: []).

Expected fix

For Desktop/sidebar/history calls that are intended to show all local history, please pass an empty provider filter instead of null, for example:

const ALL_MODEL_PROVIDERS: string[] = [];

request(thread/list, {
  ...params,
  modelProviders: ALL_MODEL_PROVIDERS,
});

model_provider should remain session metadata for compatibility/resume decisions, but it should not hide local history unless the UI explicitly applies a provider filter.