Skip to content

Do not force OpenCode Zen fallback when config.toml selects a custom provider #190

@Hummer12007

Description

@Hummer12007

Summary

When codexapp runs without usable Codex OAuth tokens but ~/.codex/config.toml explicitly selects a custom/model provider, it still synthesizes the unauthenticated OpenCode Zen fallback. That starts codex app-server with model_provider="opencode_zen", overriding the user configured provider.

In my setup, config.toml selects Azure, but requests were routed through the local OpenCode Zen proxy until I created a disabled provider-state file.

Reproduction

  1. Configure ~/.codex/config.toml with an explicit provider, for example:
model = "gpt-5.5"
model_provider = "azure"

[model_providers.azure]
# Azure provider config here
  1. Have no ~/.codex/webui-custom-providers.json file.
  2. Have no Codex OAuth auth file, or have an auth.json that does not contain tokens.access_token. My local auth.json only had top-level provider API key names, not tokens.*.
  3. Start codexapp, for example:
npx codexapp --no-password --no-login
  1. Inspect the spawned codex app-server process args or send a request.

Actual behavior

The spawned app-server receives OpenCode Zen as the active provider override, e.g.:

-c model="big-pickle"
-c model_provider="opencode_zen"
-c model_providers.opencode_zen.base_url="http://127.0.0.1:<port>/codex-api/zen-proxy/v1"
-c model_providers.opencode_zen.wire_api="responses"

That overrides the explicit model_provider = "azure" in config.toml, so traffic goes through the Zen proxy path.

Expected behavior

If ~/.codex/config.toml explicitly sets model_provider, codexapp should respect that provider and should not synthesize the unauthenticated OpenCode Zen fallback. The fallback should only apply to truly unconfigured/no-auth setups.

Code path observed

The behavior appears to come from this path:

  • buildAppServerConfig() calls ensureDefaultFreeModeStateForMissingAuthSync(...).
  • hasUsableCodexAuthSync() only treats auth.tokens.access_token as usable auth.
  • With no provider-state file and no usable Codex OAuth token, shouldCreateDefaultFreeModeStateForMissingAuth(null, false) returns true.
  • createDefaultOpenCodeZenFreeModeState() returns the Zen fallback state.
  • getFreeModeConfigArgs() adds model_provider="opencode_zen".

Workaround

Creating this file disables the fallback and lets config.toml win again:

{"enabled":false,"apiKey":null,"model":"openrouter/free","provider":"openrouter","wireApi":"responses"}

at:

~/.codex/webui-custom-providers.json

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions