Codex Desktop lists threads from a removed custom provider, then fails to open them
What version of the Codex App are you using (From “About Codex” dialog)?
26.810.52044
What subscription do you have?
pro 20x
What platform is your computer?
Darwin 23.6.0 x86_64 i386
What issue are you seeing?
Codex Desktop continues to display a thread created with a custom model provider after that provider has been removed from ~/.codex/config.toml and the active provider has been changed back to openai.
Clicking the thread fails with the following full error:
failed to load configuration: Model provider 'custom' not found
No prompt is submitted because the error occurs while opening the thread.
This reproduces with a standalone Codex configuration. No local proxy, session migration, session mirroring, or third-party session-management process is involved. The Codex state database contains exactly one row for the affected thread, with model_provider = 'custom'; there is no duplicated openai row.
The same CODEX_HOME does not expose this unavailable thread in the normal current-provider history view in Codex CLI. This isolates the problem to Codex Desktop's cross-provider thread discovery and resume behavior.
What steps can reproduce the bug?
- Quit Codex Desktop completely.
- Make an OpenAI API key available to the Desktop process as
CODEX_REPRO_API_KEY. - Back up
~/.codex/config.toml. - Replace it with the following standalone custom-provider configuration:
```toml
model_provider = "custom"
model = "gpt-5.6-sol"
model_context_window = 450000
[model_providers.custom]
name = "Custom Provider Reproduction"
base_url = "https://api.openai.com/v1"
env_key = "CODEX_REPRO_API_KEY"
wire_api = "responses"
requires_openai_auth = false
```
- Launch Codex Desktop from the environment containing
CODEX_REPRO_API_KEY. - Create a new thread and send a prompt. Confirm that the thread works through the
customprovider. - Quit Codex Desktop completely.
- Restore a normal configuration whose active provider is
openaiand which does not contain[model_providers.custom]. For example:
``toml``
model_provider = "openai"
model = "gpt-5.6-sol"
- Relaunch Codex Desktop.
- Observe that the thread created with
customis still displayed in the Desktop sidebar. - Click the thread.
- Codex Desktop displays:
``text``
failed to load configuration: Model provider 'custom' not found
Details from my reproduced thread:
Session ID: 01a00eeb-5202-71b2-92bb-6bad3c4188ec
Recorded model provider: custom
Recorded model: gpt-5.6-sol
Recorded token usage: 51,671
Configured context window: 450,000
The failure happens before the session is loaded or a new prompt is submitted, so it is not related to reaching the token limit or context-window limit.
I also verified the absence of a mirrored openai copy with:
sqlite3 "$HOME/.codex/state_5.sqlite" \
"SELECT id, model_provider FROM threads WHERE id = '01a00eeb-5202-71b2-92bb-6bad3c4188ec';"
The query returns exactly one row:
01a00eeb-5202-71b2-92bb-6bad3c4188ec|custom
What is the expected behavior?
Codex Desktop should not present a thread as resumable when its recorded model provider is not available in the current configuration.
Either of the following behaviors would avoid the broken state:
- Filter the history list to providers available in the current configuration, consistent with the normal current-provider history view in Codex CLI; or
- Keep cross-provider threads visible, but mark threads whose provider is unavailable as unavailable and provide an actionable recovery path, such as asking the user to restore or select a provider, instead of failing when the thread is opened.
Additional information
Environment:
macOS: 14.8.7 (23J520)
Codex Desktop / ChatGPT Desktop: 26.810.52044 (build 6662)
Bundled Codex CLI: 0.148.0-alpha.9
Restoring the [model_providers.custom] definition makes the thread usable again, confirming that the persisted thread still belongs to custom and is not corrupted.
The behavior can make normal cross-provider history look like duplicated or corrupted conversations. More importantly, it leaves a visible history entry that cannot be opened whenever its original provider definition is no longer present.