Skip to content

bug: Codex WebSocket 401 — model_provider incorrectly nested inside [shell_environment_policy] in generated TOML config #27957

Description

@lpcox

Summary

PR #27711 added supports_websockets = false via an openai-proxy model provider in the Codex TOML config, but the generated TOML has a key-ordering bug that causes Codex to silently ignore the model_provider = "openai-proxy" directive and fall back to the default OpenAI provider — which still uses WebSockets → 401 Unauthorized.

Root Cause

In TOML, all key-value pairs following a [table] header belong to that table. In the generated config.toml, model_provider = "openai-proxy" is emitted after the [shell_environment_policy] table header, making it a sub-key of shell_environment_policy rather than a root-level Codex directive.

Broken output (current):

[shell_environment_policy]         # ← table opened first
inherit = "core"
include_only = [...]

model_provider = "openai-proxy"   # ← INSIDE [shell_environment_policy]! Bug.

[model_providers.openai-proxy]
name = "OpenAI AWF proxy"
base_url = "http://172.30.0.30:10000"
env_key = "OPENAI_API_KEY"
supports_websockets = false

Correct output (needed):

model_provider = "openai-proxy"   # ← root level ✓

[model_providers.openai-proxy]
name = "OpenAI AWF proxy"
base_url = "http://172.30.0.30:10000"
env_key = "OPENAI_API_KEY"
supports_websockets = false

[shell_environment_policy]
inherit = "core"
include_only = [...]

Code Location

File: pkg/workflow/codex_mcp.go

The issue is the call order inside RenderMCPConfig():

yaml.WriteString("cat > \"/tmp/gh-aw/mcp-config/config.toml\" << " + shellPolicyDelimiter + "\n")
e.renderShellEnvironmentPolicyToml(yaml, ...)    // emits [shell_environment_policy] FIRST
if isFirewallEnabled(workflowData) {
    e.renderOpenAIProxyProviderToml(yaml, ...)   // emits model_provider AFTER → inside the table!
}
yaml.WriteString(shellPolicyDelimiter + "\n")

Fix

Swap the call order so renderOpenAIProxyProviderToml is called before renderShellEnvironmentPolicyToml:

yaml.WriteString("cat > \"/tmp/gh-aw/mcp-config/config.toml\" << " + shellPolicyDelimiter + "\n")
if isFirewallEnabled(workflowData) {
    e.renderOpenAIProxyProviderToml(yaml, ...)   // root-level keys first ✓
}
e.renderShellEnvironmentPolicyToml(yaml, ...)    // table header after ✓
yaml.WriteString(shellPolicyDelimiter + "\n")

Evidence

Failing run (smoke-codex, branch copilot/fix-supports-websockets-flag):

Successful run for comparison (gh-aw-firewall, compiled with correct ordering):

The working run's lock file places model_provider = "openai-proxy" before [shell_environment_policy], so Codex correctly picks it up as a root-level config key.

Impact

All Codex smoke/CI runs using --enable-api-proxy with Codex 0.121.0+ (which prefers gpt-5.3-codex over WebSocket) will fail with WebSocket 401 despite PR #27711 being merged.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions