Skip to content

fix(3.1.10): heal legacy openai/<gpt> configs on startup (OAuth 401 Missing bearer) - #266

Merged
yalexx merged 1 commit into
betafrom
fix/v3.1.10-openai-oauth-startup-migration
Jul 21, 2026
Merged

fix(3.1.10): heal legacy openai/<gpt> configs on startup (OAuth 401 Missing bearer)#266
yalexx merged 1 commit into
betafrom
fix/v3.1.10-openai-oauth-startup-migration

Conversation

@yalexx

@yalexx yalexx commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Problem (customer report, box on 3.1.5)

FailoverError: 401 Unauthorized: Missing bearer or basic authentication in header, url: https://api.openai.com/v1/responses — ChatGPT (OAuth) user, no API key. Worked for days, then died.

Root cause

The device stored agents.defaults.model.primary (and/or a fallbacks entry) as openai/gpt-5.5 from before the setup UI routed ChatGPT picks through Codex. With Codex-OAuth auth and no OpenAI API key, openai/* resolves to api.openai.com with no bearer → 401. It surfaces as a FailoverError days in because the codex primary works until the OAuth token first refreshes, then failover reaches the keyless openai/* fallback.

src/app/setup-api/chat/model/route.ts (shipped v3.1.7) already rewrites openai/<gpt>codex/<gpt>but only when the user re-picks the model. Existing configs never re-pick, so a box updated 3.1.5 → 3.1.9 stays broken until the model is manually re-selected. That's the gap this closes.

Fix

Extend the startup migration in scripts/gateway-pre-start.sh (right after the retired-Sonnet migration) to rewrite openai/<codex-supported gpt>codex/<gpt> for primary + every fallback, guarded on codex OAuth present AND no OpenAI API key — so keyed / dual-auth boxes (where openai/* is valid) are untouched. Mirrors CODEX_SUPPORTED_MODEL_RE / hasOpenAiApiKeyProfile / hasCodexOauthProfile from the chat-model route.

Testing (6 fixtures, real extracted block)

case result
codex-OAuth, no key: openai/gpt-5.5 + fallback openai/gpt-5.4 codex/gpt-5.5, codex/gpt-5.4
openai API key present unchanged ✅
non-supported openai/gpt-4o primary left as-is ✅
already codex/gpt-5.5 no-op ✅
no codex auth unchanged ✅
retired Sonnet + keyless fallback Sonnet→gemma, fallback→codex (composes) ✅

bash -n and python3 -m py_compile pass. Only scripts/gateway-pre-start.sh changed (+64 lines).

Note for release assembly

Targets beta (3.1.10), which already carries the routing fix + gateway-recovery hardening (#263). Pending on-box smoke test (box 192.168.50.144) before promoting to main.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved configuration migration for legacy ChatGPT subscription setups.
    • Automatically updates supported GPT model references for Codex OAuth configurations when no OpenAI API credentials are present.
    • Preserves existing model settings when OpenAI credentials are configured or Codex authentication is unavailable.

ChatGPT-subscription boxes (Codex OAuth, no OpenAI API key) that stored
their active model or a fallback as `openai/gpt-5.5` (etc.) before the setup
UI routed ChatGPT picks through Codex hit `401 Missing bearer or basic
authentication in header` on api.openai.com/v1/responses — often only as a
FailoverError days into use, once the OAuth token first refreshes and the
failover chain reaches the keyless `openai/*` fallback.

The chat-model pick route already rewrites openai/<gpt> -> codex/<gpt>, but
only when the user re-picks the model; existing configs never re-pick, so an
updated box stays broken until manually re-selected. Migrate primary +
fallbacks in gateway-pre-start.sh on gateway start, guarded on "codex OAuth
present AND no OpenAI API key" so keyed / dual-auth boxes (where openai/* is a
valid route) are left untouched. Mirrors CODEX_SUPPORTED_MODEL_RE /
hasOpenAiApiKeyProfile / hasCodexOauthProfile in
src/app/setup-api/chat/model/route.ts.

Verified against 6 fixtures: openai->codex primary+fallback migrate; keyed
box untouched; non-supported (gpt-4o) primary left as-is; already-codex no-op;
no-codex-auth untouched; composes with the retired-Sonnet migration. bash -n
and py_compile pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yalexx
yalexx requested a review from a team as a code owner July 21, 2026 10:11
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The gateway pre-start migration now translates supported openai/<gpt> primary and fallback model IDs to codex/<gpt> when Codex OAuth is configured without OpenAI API credentials.

Changes

Codex model migration

Layer / File(s) Summary
Conditional model ID translation
scripts/gateway-pre-start.sh
Detects Codex OAuth-only authentication, rewrites supported primary and fallback model IDs, and records configuration changes.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: krasimirkralev

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is clear, concise, and accurately describes the legacy startup migration fix.
Description check ✅ Passed The description covers the problem, root cause, fix, and testing, matching the template's main sections.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/v3.1.10-openai-oauth-startup-migration

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

🦀 ClawReview

Fresh PR washed in with the tide — here's the gist.

This PR fixes a silent 401 ('Missing bearer') that hit ChatGPT-subscription users who updated from 3.1.5+: their device kept openai/gpt-5.5 as the active or fallback model from before the setup UI routed ChatGPT picks through Codex, so once the OAuth token refreshed and failover reached the keyless openai/* entry, the gateway surfaced a FailoverError — sometimes days after the update. The fix extends the existing startup migration in gateway-pre-start.sh to rewrite legacy openai/<codex-supported gpt> IDs to codex/<gpt> at gateway launch, guarded so API-key users and dual-auth boxes are left untouched.

At a glance

  • 🔧 Fix · touches gateway pre-start migration script + AI model config (openclaw.json)
  • Base branch: beta · +64 source / +0 tests across 1 file
  • ✅ base beta matches the beta-first convention
  • ✅ conventional PR title
  • ℹ️ touches security-sensitive paths (scripts/gateway-pre-start.sh) — review with extra care

Good to know

  • 🟡 Runs at every gateway startup on customer hardware and mutates ~/.openclaw/openclaw.json — the migration is idempotent and carefully guarded, but it's touching live customer state on device boot.
  • ℹ️ The 64 new lines are Python embedded inside the shell script, consistent with the existing migration pattern in the same file (retired-Sonnet block above it).
  • 🟡 Six test cases are documented in the PR body as a manual fixture table; no automated test files are added alongside the script change.
  • ℹ️ Targets beta (3.1.10) and is pending an on-box smoke test before promotion to main — PR Promote v3.1.10 gateway recovery to main #264 is the promotion vehicle when ready.

— ClawReview 🦀, scuttling off. General info only — see CodeRabbit for the detailed review. Conventions: docs.

@github-actions github-actions Bot added the area: install Auto-triage area label Jul 21, 2026
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

CI Summary

✅ Tests

  • Result: passed
  • View run
  • Coverage: statements 69.77%, branches 59.68%, functions 65.16%, lines 71.79%

✅ E2E

✅ E2E Install

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/gateway-pre-start.sh`:
- Around line 188-195: Update _has_codex_oauth_profile to recognize both “codex”
and the legacy “openai-codex” provider values when mode is “oauth”. Preserve the
existing profile filtering and normalization behavior so either provider
triggers the migration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b397a7dd-9a27-4cdd-8216-eaf672600095

📥 Commits

Reviewing files that changed from the base of the PR and between 22fa9ba and 8e66cd9.

📒 Files selected for processing (1)
  • scripts/gateway-pre-start.sh

Comment on lines +188 to +195
def _has_codex_oauth_profile():
for _entry in _auth_profiles():
if not isinstance(_entry, dict):
continue
_p = str(_entry.get("provider", "")).strip().lower()
_m = str(_entry.get("mode", "")).strip().lower()
if _p == "codex" and _m == "oauth":
return True

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Recognize legacy openai-codex OAuth profiles.

This only accepts provider == "codex", although this script still treats openai-codex as a legacy Codex provider. Those OAuth-only devices will skip this migration and retain the openai/<gpt> IDs that cause the reported 401.

Proposed fix
-        if _p == "codex" and _m == "oauth":
+        if _p in ("codex", "openai-codex") and _m == "oauth":
             return True
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _has_codex_oauth_profile():
for _entry in _auth_profiles():
if not isinstance(_entry, dict):
continue
_p = str(_entry.get("provider", "")).strip().lower()
_m = str(_entry.get("mode", "")).strip().lower()
if _p == "codex" and _m == "oauth":
return True
def _has_codex_oauth_profile():
for _entry in _auth_profiles():
if not isinstance(_entry, dict):
continue
_p = str(_entry.get("provider", "")).strip().lower()
_m = str(_entry.get("mode", "")).strip().lower()
if _p in ("codex", "openai-codex") and _m == "oauth":
return True
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/gateway-pre-start.sh` around lines 188 - 195, Update
_has_codex_oauth_profile to recognize both “codex” and the legacy “openai-codex”
provider values when mode is “oauth”. Preserve the existing profile filtering
and normalization behavior so either provider triggers the migration.

@yalexx
yalexx merged commit 120fcd3 into beta Jul 21, 2026
8 checks passed
@yalexx
yalexx deleted the fix/v3.1.10-openai-oauth-startup-migration branch July 21, 2026 10:52
yalexx added a commit that referenced this pull request Jul 22, 2026
* Harden gateway recovery after updates (#263)

* fix: migrate legacy openai/<gpt> model+fallbacks to codex on startup (#266)

ChatGPT-subscription boxes (Codex OAuth, no OpenAI API key) that stored
their active model or a fallback as `openai/gpt-5.5` (etc.) before the setup
UI routed ChatGPT picks through Codex hit `401 Missing bearer or basic
authentication in header` on api.openai.com/v1/responses — often only as a
FailoverError days into use, once the OAuth token first refreshes and the
failover chain reaches the keyless `openai/*` fallback.

The chat-model pick route already rewrites openai/<gpt> -> codex/<gpt>, but
only when the user re-picks the model; existing configs never re-pick, so an
updated box stays broken until manually re-selected. Migrate primary +
fallbacks in gateway-pre-start.sh on gateway start, guarded on "codex OAuth
present AND no OpenAI API key" so keyed / dual-auth boxes (where openai/* is a
valid route) are left untouched. Mirrors CODEX_SUPPORTED_MODEL_RE /
hasOpenAiApiKeyProfile / hasCodexOauthProfile in
src/app/setup-api/chat/model/route.ts.

Verified against 6 fixtures: openai->codex primary+fallback migrate; keyed
box untouched; non-supported (gpt-4o) primary left as-is; already-codex no-op;
no-codex-auth untouched; composes with the retired-Sonnet migration. bash -n
and py_compile pass.

Co-authored-by: Mike (IDRobots) <mike@idrobots.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* fix(3.1.10): responsive chat header pills (wrap instead of overlap on narrow chat) (#267)

* fix: chat header pills squeeze + truncate cleanly on narrow panels

On a narrow chat the provider / model / thinking selector pills overlapped
into an unreadable strip. Two parts:

1. .header-dropdown-trigger gets width:100% so the button fills its
   flex-shrinking .header-dropdown parent. Previously the button kept its
   content width and spilled past the shrunk parent, so overflow:hidden on
   .chat-header-pills clipped / overlapped the pills instead of the labels
   truncating. Now every pill gives ground evenly and its label ellipsizes
   (the chevron stays — it's reserved in the 24px right padding).

2. Single row (no wrap) + overflow:hidden, and the chat window clamps to
   MIN_CHAT_WIDTH (340px) on both resize paths + the rendered width, so the
   window stops shrinking once the pills reach a readable minimum instead of
   smashing them.

The open menu is portaled to <body> (HeaderDropdown), so clipping the row
can't hide it. Verified at 320-420px: even truncation, carets visible, zero
overlap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: open chat from mascot with a macOS-style animation, no corner flash

- Stop streaming the frozen mascot's position into mascotX while the chat is
  open (page.tsx). That nudged mascotX for a frame right after opening, so the
  popup flashed to the wrong corner before settling. mascotX is now captured
  once from the tap.
- Grow the popup OUT of the mascot: transform-origin pinned to the popup's
  bottom edge, aligned horizontally with the mascot, and scale 0.82 -> 1 on an
  easeOutExpo curve (cubic-bezier(0.16,1,0.3,1)) over 0.36s. Smooth, premium,
  emanates from where you tapped instead of scaling from the popup centre.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore: bump SW cache clawbox-v3 -> v4 to invalidate stale assets on the 3.1.10 chat-UI changes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: keep chat popup header on-screen on short/zoomed viewports

The un-dragged popup anchors from the bottom (bottom:170 above the mascot,
bottom:65 in tray mode) but its maxHeight budget was a flat 100vh-60px, so on
viewports shorter than ~680px (small windows, browser zoom) a 500px-tall popup
shoved its whole header — pills, status dot, close button — off the TOP of the
screen (rect.y = -76 measured on a 594px viewport). Subtract the bottom anchor
from the height budget per mode (+12px top margin) so the header is always
visible and the popup just gets shorter instead.

Found by driving the real desktop over CDP and sampling the popup rect during
open; the same probe confirmed the mascot-open animation runs and there is no
left-corner flash.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Mike (IDRobots) <mike@idrobots.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Mike (IDRobots) <mike@idrobots.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: install Auto-triage area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant