openclaw - ✅(Solved) Fix [Bug]: openai/gpt-image-2 via Codex OAuth fails with HTTP 403 when openai-codex.baseUrl is the legacy /backend-api form (no /codex) [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#71460Fetched 2026-04-26 05:12:30
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
referenced ×2closed ×1commented ×1cross-referenced ×1

openai/gpt-image-2 over OpenAI Codex OAuth fails with HTTP 403 when models.providers.openai-codex.baseUrl is the legacy https://chatgpt.com/backend-api (no /codex segment), because the image path builds the request URL verbatim while the chat path silently canonicalizes it.

Root Cause

openai/gpt-image-2 over OpenAI Codex OAuth fails with HTTP 403 when models.providers.openai-codex.baseUrl is the legacy https://chatgpt.com/backend-api (no /codex segment), because the image path builds the request URL verbatim while the chat path silently canonicalizes it.

Fix Action

Fix / Workaround

baseUrl in configDist patched?Result
https://chatgpt.com/backend-apinoHTTP 403, silent fallback to fal-ai/flux/dev
https://chatgpt.com/backend-api/codexnoHTTP 200, model: gpt-image-2, valid PNG
https://chatgpt.com/backend-apiyes (local canonicalization)HTTP 200, model: gpt-image-2, valid PNG
https://chatgpt.com/backend-api/codexyesHTTP 200, model: gpt-image-2, valid PNG

PR fix notes

PR #71461: fix(openai): canonicalize Codex Responses baseUrl in image generation

Description (problem / solution / changelog)

Summary

  • Problem: openai/gpt-image-2 over Codex OAuth 403s when models.providers.openai-codex.baseUrl is the legacy https://chatgpt.com/backend-api form. Image path POSTs to /backend-api/responses (retired by OpenAI on 2026-04) while chat path silently canonicalizes to /backend-api/codex/responses.
  • Why it matters: Auto-fallback hides the failure by serving an image from fal-ai/flux/dev, so users believe gpt-image-2 is working but receive results from a different provider and miss their Codex entitlement.
  • What changed: Add canonicalizeCodexResponsesBaseUrl in extensions/openai/base-url.ts and call it from generateOpenAICodexImage before resolveProviderHttpRequestConfig. Mirrors the chat-path normalization in normalizeCodexTransportFields (extensions/openai/openai-codex-provider.ts:147).
  • What did NOT change (scope boundary): chat path normalization, default-baseUrl behavior when openai-codex.baseUrl is unset, non-Codex baseUrl handling (private proxies and Azure-style endpoints pass through unchanged), media-understanding/video paths, SSRF/dispatcher policy, and the silent-fallback behavior fixed separately in fbf8b216c6.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #71460
  • Related #70703, #71290 (both closed; do not fully resolve this normalization gap)
  • This PR fixes a bug or regression

Root Cause

  • Root cause: The image path reads req.cfg?.models?.providers?.["openai-codex"]?.baseUrl and passes it through resolveProviderHttpRequestConfig without canonicalization, then constructs ${baseUrl}/responses. The chat path runs the same configured value through normalizeCodexTransportFields, which hard-overrides any isOpenAICodexBaseUrl match to the canonical OPENAI_CODEX_BASE_URL (with the /codex segment). The image path was added in c84a2f5244 and hardened in c2cf3c49d3 but never picked up the chat-path normalization, so a config that was always tolerated by chat became broken for image generation when OpenAI retired the /backend-api/responses alias on 2026-04 (acknowledged in the existing extensions/openai/base-url.test.ts:19 comment).
  • Missing detection / guardrail: No regression test asserted that a legacy openai-codex.baseUrl produced a request URL ending in /codex/responses. Existing Codex image tests pinned the canonical form already and a custom-base-url test (http://127.0.0.1:44220/backend-api/codex) used the canonical shape, so the gap was invisible.
  • Contributing context: The chat-path canonicalization lives inside normalizeCodexTransportFields rather than as a reusable helper. A shared canonicalization helper makes this fix small and lets future Codex Responses transports (media understanding, video) reuse the same shape.

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/openai/base-url.test.ts (helper unit) and extensions/openai/image-generation-provider.test.ts (integration at the request URL boundary).
  • Scenario the test should lock in: When models.providers.openai-codex.baseUrl = "https://chatgpt.com/backend-api" and the image path is selected, the captured postJsonRequest URL is https://chatgpt.com/backend-api/codex/responses.
  • Why this is the smallest reliable guardrail: The bug surfaces at the request URL boundary; asserting the URL string captures any future regression cheaply (no live HTTP, no SSE parsing, no auth flow). The helper unit test pins the canonicalization contract independently of the image provider so it can be reused safely by media-understanding or video paths later.
  • Existing test that already covers this: extensions/openai/openai-codex-provider.test.ts covers the chat path, but does not catch this image-side regression.
  • If no new test is added, why not: N/A; new tests added.

User-visible / Behavior Changes

  • Existing users who set models.providers.openai-codex.baseUrl to the legacy https://chatgpt.com/backend-api will now have openai/gpt-image-2 work over Codex OAuth instead of 403'ing into a silent provider fallback. Users who already use the canonical form, or who do not set a baseUrl at all (relying on the default), see no change. Users who set a custom non-Codex baseUrl (private proxy, Azure-style endpoint) see no change.

Diagram

Before (legacy baseUrl in config):
  cfg.models.providers.openai-codex.baseUrl
    = "https://chatgpt.com/backend-api"
  ─> generateOpenAICodexImage
    ─> resolveProviderHttpRequestConfig (no normalization)
    ─> POST https://chatgpt.com/backend-api/responses
    ─> HTTP 403 (alias retired 2026-04)
    ─> media-generation candidate fallback to fal-ai/flux/dev
    ─> user receives image NOT from gpt-image-2

After (legacy baseUrl in config):
  cfg.models.providers.openai-codex.baseUrl
    = "https://chatgpt.com/backend-api"
  ─> generateOpenAICodexImage
    ─> canonicalizeCodexResponsesBaseUrl
       returns "https://chatgpt.com/backend-api/codex"
    ─> resolveProviderHttpRequestConfig
    ─> POST https://chatgpt.com/backend-api/codex/responses
    ─> HTTP 200, gpt-image-2 PNG returned

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No — existing Codex Responses POST, just with a corrected URL.
  • Command/tool execution surface changed? No
  • Data access scope changed? No

The only behavioral change is which URL the existing Codex OAuth Bearer token is sent to. The new helper is a pure string transformation with no side effects, no network access, and no token handling. Non-Codex baseUrls (e.g., private proxies, Azure-style endpoints) pass through unchanged so SSRF guards and dispatcher policies continue to apply exactly as before.

Repro + Verification

Environment

  • OS: Ubuntu 24.04 (Linux 6.8.0-110-generic)
  • Runtime/container: Node 22.22.0, npm global install
  • Model/provider: openai/gpt-image-2 over openai-codex OAuth
  • Integration/channel: CLI (openclaw capability image generate)
  • Relevant config (redacted):
{
  "models": {
    "providers": {
      "openai-codex": {
        "baseUrl": "https://chatgpt.com/backend-api",
        "api": "openai-codex-responses"
      }
    }
  }
}

Steps

  1. Install OpenClaw 2026.4.23 globally; configure openai-codex OAuth (no OPENAI_API_KEY).
  2. Set models.providers.openai-codex.baseUrl = "https://chatgpt.com/backend-api" (legacy form, no /codex).
  3. openclaw capability image generate --model openai/gpt-image-2 --prompt "smoke" --output before.png.

Expected

gpt-image-2 PNG returned via Codex OAuth, request POSTed to https://chatgpt.com/backend-api/codex/responses.

Actual (before fix)

CLI exits 0, but logs show:

[image-generation/openai] image auth selected: provider=openai-codex mode=oauth transport=codex-responses requestedModel=gpt-image-2 responsesModel=gpt-5.4 timeoutMs=180000
[image-generation] candidate failed: openai/gpt-image-2: OpenAI Codex image generation failed (HTTP 403): <html> ...
model: fal-ai/flux/dev

The image is delivered by fal-ai/flux/dev, not gpt-image-2.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets

Local matrix verified on the user's 2026.4.23 (a979721) global install:

baseUrl in configLocal code patchResult
https://chatgpt.com/backend-apinone403, silent fallback to fal-ai/flux/dev
https://chatgpt.com/backend-api/codexnone200, model: gpt-image-2, 1024x1024 PNG, 855 KB
https://chatgpt.com/backend-apidist canonicalization mirror of this PR200, model: gpt-image-2, 1024x1024 PNG, 823 KB
https://chatgpt.com/backend-api/codexdist canonicalization mirror of this PR200, model: gpt-image-2, 1024x1024 PNG, 1021 KB

CI / local validation:

  • pnpm test extensions/openai/base-url.test.ts extensions/openai/image-generation-provider.test.ts -> 43 passed (39 existing + 4 new helper cases + 1 new integration regression).
  • pnpm format:check on touched files: clean.
  • Scoped lint via oxlint on touched files: 0 warnings, 0 errors.
  • pnpm tsgo:prod shows 0 new TS errors from this PR's touched files. The 131 errors that surface on origin/main are all in unrelated files (src/plugin-sdk/provider-tools.ts, ui/src/ui/..., extensions/openai/{transport-policy,tts,video-generation-provider}.ts) and pre-date this branch.

Human Verification

  • Verified scenarios:
    • Live image generation via openclaw capability image generate --model openai/gpt-image-2 against a real Codex OAuth profile, with both legacy and canonical baseUrl values.
    • Confirmed the request reaches /backend-api/codex/responses (200) instead of /backend-api/responses (403) when the patched code runs.
    • Confirmed silent fallback to fal-ai/flux/dev only happens before the fix; after the fix, gpt-image-2 is the actual provider on the returned image.
  • Edge cases checked:
    • Helper returns undefined for undefined, the original empty/whitespace string for ""/" ", the canonical form for legacy variants (/backend-api, /backend-api/, /backend-api/v1), and the canonical form unchanged for already-canonical inputs (/backend-api/codex, /backend-api/codex/v1).
    • Helper passes through non-Codex URLs unchanged (https://api.openai.com/v1, https://my-proxy.example.com/openai-codex, https://chatgpt.com).
    • Existing test using http://127.0.0.1:44220/backend-api/codex still passes -> custom Codex transport overrides keep working.
  • What I did not verify:
    • Live SSE response-shape edge cases (the SSE parser is unchanged; existing tests cover it).
    • Non-Linux platforms (the change is platform-agnostic string transformation).

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Existing configs work unchanged. Users with the legacy baseUrl form get strictly improved behavior (image gen now succeeds where it previously 403'd into a silent fallback). Users with canonical baseUrl, default baseUrl, or non-Codex baseUrls see no behavioral change.

Risks and Mitigations

  • Risk: A user is relying on the image path 403'ing the legacy URL as a deliberate routing signal.
    • Mitigation: Implausible — the 403 was silently masked by mediaGenerationAutoProviderFallback, so no user could observe it as a deterministic signal. Documented behavior promises Codex OAuth image gen and the chat path already canonicalized the same URL.
  • Risk: Future Codex Responses URL convention changes (e.g., a new /v2 path) re-introduce a similar gap.
    • Mitigation: The new helper centralizes the canonicalization and pairs with isOpenAICodexBaseUrl, so a future change updates one regex and one constant. Adjacent surfaces (media-understanding, video) can adopt the same helper in a follow-up.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/openai/base-url.test.ts (modified, +44/-1)
  • extensions/openai/base-url.ts (modified, +13/-0)
  • extensions/openai/image-generation-provider.test.ts (modified, +42/-0)
  • extensions/openai/image-generation-provider.ts (modified, +7/-1)

Code Example

[image-generation/openai] image auth selected: provider=openai-codex mode=oauth transport=codex-responses requestedModel=gpt-image-2 responsesModel=gpt-5.4 timeoutMs=180000
[image-generation] candidate failed: openai/gpt-image-2: OpenAI Codex image generation failed (HTTP 403): <html> <head> ... </head>
model: fal-ai/flux/dev

---

{
  "models": {
    "providers": {
      "openai-codex": {
        "baseUrl": "https://chatgpt.com/backend-api",
        "api": "openai-codex-responses"
      }
    }
  },
  "agents": {
    "defaults": {
      "imageGenerationModel": { "primary": "openai/gpt-image-2" }
    }
  }
}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

openai/gpt-image-2 over OpenAI Codex OAuth fails with HTTP 403 when models.providers.openai-codex.baseUrl is the legacy https://chatgpt.com/backend-api (no /codex segment), because the image path builds the request URL verbatim while the chat path silently canonicalizes it.

Steps to reproduce

  1. Run OpenClaw 2026.4.23 (a979721) with a working openai-codex OAuth profile and no OPENAI_API_KEY.
  2. In ~/.openclaw/openclaw.json, set models.providers.openai-codex.baseUrl to "https://chatgpt.com/backend-api" (legacy form, no /codex).
  3. Run openclaw capability image generate --model openai/gpt-image-2 --prompt "test".

Expected behavior

Image is generated by gpt-image-2 over Codex OAuth, identical to the chat path which already accepts the legacy baseUrl form. The chat path canonicalizes the URL in extensions/openai/openai-codex-provider.ts:147 (normalizeCodexTransportFields) and successfully POSTs to https://chatgpt.com/backend-api/codex/responses.

Actual behavior

CLI succeeds (exit 0) but logs show:

[image-generation/openai] image auth selected: provider=openai-codex mode=oauth transport=codex-responses requestedModel=gpt-image-2 responsesModel=gpt-5.4 timeoutMs=180000
[image-generation] candidate failed: openai/gpt-image-2: OpenAI Codex image generation failed (HTTP 403): <html> <head> ... </head>
model: fal-ai/flux/dev

The image path constructs ${baseUrl}/responses at extensions/openai/image-generation-provider.ts:567, which yields https://chatgpt.com/backend-api/responses. OpenAI retired the /backend-api/responses alias server-side on 2026-04 (acknowledged in extensions/openai/base-url.test.ts:19), so the request 403s. With auto-fallback active, the agent silently shifts to fal-ai/flux/dev and the user receives an image that is not from gpt-image-2.

OpenClaw version

2026.4.23 (a979721)

Operating system

Ubuntu 24.04 (Linux 6.8.0-110-generic)

Install method

npm global (npm install -g openclaw)

Model

openai/gpt-image-2

Provider / routing chain

openclaw -> openai-codex (OAuth) -> chatgpt.com Codex Responses backend

Additional provider/model setup details

Sammy auth profile, OpenAI Codex OAuth, ChatGPT Pro plan. Relevant config (redacted):

{
  "models": {
    "providers": {
      "openai-codex": {
        "baseUrl": "https://chatgpt.com/backend-api",
        "api": "openai-codex-responses"
      }
    }
  },
  "agents": {
    "defaults": {
      "imageGenerationModel": { "primary": "openai/gpt-image-2" }
    }
  }
}

models.providers.openai is not set. OPENAI_API_KEY is not set. Codex OAuth is freshly refreshed and confirmed working for chat (gpt-5.4, gpt-5.5).

Logs, screenshots, and evidence

Side-by-side reproduction:

baseUrl in configDist patched?Result
https://chatgpt.com/backend-apinoHTTP 403, silent fallback to fal-ai/flux/dev
https://chatgpt.com/backend-api/codexnoHTTP 200, model: gpt-image-2, valid PNG
https://chatgpt.com/backend-apiyes (local canonicalization)HTTP 200, model: gpt-image-2, valid PNG
https://chatgpt.com/backend-api/codexyesHTTP 200, model: gpt-image-2, valid PNG

Code references:

  • Image path (no normalization): extensions/openai/image-generation-provider.ts:534-548, request URL built at line 567 as ${baseUrl}/responses.
  • Chat path (with normalization): extensions/openai/openai-codex-provider.ts:129-149, line 147 hard-overrides any isOpenAICodexBaseUrl match to OPENAI_CODEX_BASE_URL.
  • Existing helper: extensions/openai/base-url.ts:11-18 accepts both /backend-api and /backend-api/codex as isOpenAICodexBaseUrl(true).
  • Server-side context: extensions/openai/base-url.test.ts:18-19 notes "OpenAI removed the /backend-api/responses alias server-side on 2026-04".

Related closed issues that touched adjacent surface but did not fix this normalization gap:

  • #70703 ([Feature]: support gpt-image-2 in image_generate via Codex OAuth) closed 2026-04-23. The closing thread contains a comment from openclaud11-sys reporting the same /codex baseUrl gap on a different install, but the resolution treated it as user config.
  • #71290 ([Bug]: openai/gpt-image-2 via OpenAI Codex OAuth returns HTTP 403; agent image_generate may still fall back...) closed 2026-04-24. Fixed the silent-fallback half on main in fbf8b216c6 (post-2026.4.23). Closing comment frames the remaining 403 as account/backend gating, but the evidence above proves the same Codex OAuth profile reaches /backend-api/codex/responses successfully when the URL is canonical.

Impact and severity

  • Affected users: any OpenClaw user on 2026.4.23 (and likely earlier 2026.4.x versions that include the Codex OAuth image route at c84a2f5244) who has models.providers.openai-codex.baseUrl set to the legacy https://chatgpt.com/backend-api form. This shape is common because the chat path historically accepted it and isOpenAICodexBaseUrl still recognizes it as valid.
  • Severity: blocks the documented openai/gpt-image-2 via Codex OAuth workflow advertised in docs/tools/image-generation.md. Users see images returned but they come from a different provider, which is worse than a hard failure because it appears to work.
  • Frequency: every image_generate call while the legacy baseUrl is configured.
  • Consequence: missed product capability (gpt-image-2 quality + Codex billing entitlement), confusing user experience because the silent fallback hides the failure, wasted Codex OAuth refresh cycles while debugging.

Suggested fix

Mirror the chat-path canonicalization in the image path. PR coming in a follow-up: add canonicalizeCodexResponsesBaseUrl to extensions/openai/base-url.ts and call it inside generateOpenAICodexImage before passing baseUrl into resolveProviderHttpRequestConfig. Non-Codex baseUrls (private proxies, Azure-style endpoints) pass through unchanged.

extent analysis

TL;DR

Update the models.providers.openai-codex.baseUrl to include the /codex segment to fix the HTTP 403 issue with OpenAI Codex OAuth.

Guidance

  • Verify that the models.providers.openai-codex.baseUrl is set to the legacy https://chatgpt.com/backend-api form, which is causing the issue.
  • Update the baseUrl to https://chatgpt.com/backend-api/codex to match the expected format.
  • Consider implementing the suggested fix of mirroring the chat-path canonicalization in the image path by adding a canonicalizeCodexResponsesBaseUrl function.
  • Test the image generation with the updated baseUrl to ensure it works as expected.

Example

No code snippet is provided as the issue is related to configuration and not code.

Notes

The issue is specific to OpenClaw version 2026.4.23 and earlier versions that include the Codex OAuth image route. The suggested fix is to update the baseUrl to include the /codex segment, which should resolve the HTTP 403 issue.

Recommendation

Apply the workaround by updating the models.providers.openai-codex.baseUrl to https://chatgpt.com/backend-api/codex to fix the issue. This is a temporary solution until the suggested fix is implemented.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Image is generated by gpt-image-2 over Codex OAuth, identical to the chat path which already accepts the legacy baseUrl form. The chat path canonicalizes the URL in extensions/openai/openai-codex-provider.ts:147 (normalizeCodexTransportFields) and successfully POSTs to https://chatgpt.com/backend-api/codex/responses.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: openai/gpt-image-2 via Codex OAuth fails with HTTP 403 when openai-codex.baseUrl is the legacy /backend-api form (no /codex) [1 pull requests, 1 comments, 2 participants]