Skip to content

fix(proxy): fail over provider-local model 404s - #1354

Merged
ding113 merged 6 commits into
ding113:devfrom
Brisbanehuang:codex/provider-local-model-404-failover
Jul 22, 2026
Merged

fix(proxy): fail over provider-local model 404s#1354
ding113 merged 6 commits into
ding113:devfrom
Brisbanehuang:codex/provider-local-model-404-failover

Conversation

@Brisbanehuang

@Brisbanehuang Brisbanehuang commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • recognize the exact real upstream 404 meaning that no configured account in the current Provider group supports the requested model
  • treat that response as a Provider-local capability gap, so serial fallback, Hedge, and Discovery can continue with other Providers
  • skip redundant retries against the same Provider and bypass request rectifiers for this exact error
  • keep ordinary model_not_found and synthetic fake-200 classifications unchanged
  • preserve the existing generic 503 only when every available Provider is exhausted

Root cause

The response not supported by any configured account in this group was matched by the broad model_not_found client-error rule. One Provider could therefore abort the entire race, including a healthy in-flight candidate or a ready fallback.

This change classifies only the exact real HTTP 404 marker as RESOURCE_NOT_FOUND. It does not change ordinary model-not-found errors, fake-200 handling, or circuit-breaker accounting.

Validation

  • bunx vitest run tests/unit/proxy/provider-local-model-unavailable.test.ts tests/unit/proxy/proxy-forwarder-retry-limit.test.ts tests/unit/proxy/proxy-forwarder-hedge-first-byte.test.ts (54 tests)
  • bun run typecheck
  • bun run format:check
  • bun run lint
  • changed-file Biome checks and git diff --check

Related to #1340.

Greptile Summary

This PR makes provider-local model failures fall through to other Providers. The main changes are:

  • Detect the exact real HTTP 404 account-group capability error.
  • Classify that error as a Provider-local resource failure.
  • Skip rectification and repeated attempts against the same Provider.
  • Preserve serial fallback and active hedge candidates.
  • Keep ordinary model-not-found and synthetic-response handling unchanged.

Confidence Score: 5/5

This looks safe to merge.

  • The new classification is limited to a real HTTP 404 with the exact upstream marker.
  • Ordinary model-not-found and inferred-response paths keep their existing behavior.
  • The forwarding changes preserve fallback and active hedge candidates.
  • No blocking issue remains in the changed code.

Important Files Changed

Filename Overview
src/app/v1/_lib/proxy/errors.ts Adds narrow detection and classification for real provider-local model availability errors.
src/app/v1/_lib/proxy/forwarder.ts Bypasses rectification and same-Provider retries while preserving fallback behavior.
tests/unit/proxy/provider-local-model-unavailable.test.ts Covers the new classification and its boundaries.
tests/unit/proxy/proxy-forwarder-hedge-first-byte.test.ts Covers preservation of a healthy in-flight hedge candidate.
tests/unit/proxy/proxy-forwarder-retry-limit.test.ts Covers immediate switching without repeated attempts on the same Provider.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Upstream error] --> B{Real HTTP 404 with account-group marker?}
    B -- No --> C[Use existing classification]
    B -- Yes --> D[Classify as Provider-local resource failure]
    D --> E[Skip rectification]
    E --> F[Skip another attempt on the same Provider]
    F --> G{Another Provider or active hedge?}
    G -- Yes --> H[Continue request]
    G -- No --> I[Return exhausted-Providers response]
Loading

Reviews (5): Last reviewed commit: "Merge remote-tracking branch 'origin/dev..." | Re-trigger Greptile

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

新增 provider-local 模型不可用 404 的识别与分类逻辑,并调整转发器以跳过同供应商重试和 reactive rectifier、切换备选供应商;测试覆盖消息匹配、错误分类、hedge 行为、重试限制及 durableTerminal 回调。

Changes

Provider-local 模型 404 处理

Layer / File(s) Summary
错误识别与分类
src/app/v1/_lib/proxy/errors.ts, tests/unit/proxy/provider-local-model-unavailable.test.ts
新增错误标记常量和类型守卫,检查 404 错误消息及上游响应字段;匹配时优先分类为 RESOURCE_NOT_FOUND,并覆盖大小写、rawBody、普通 model_not_found、近似文案、非 404 状态码及推断状态码。
转发重试与供应商切换
src/app/v1/_lib/proxy/forwarder.ts, tests/unit/proxy/proxy-forwarder-hedge-first-byte.test.ts, tests/unit/proxy/proxy-forwarder-retry-limit.test.ts, tests/integration/proxy-hedge-lifecycle.test.ts
provider-local 404 不再触发同供应商重试或 reactive rectifier,并进入备选供应商切换;测试验证 hedge 候选保留、切换成功、provider chain 记录及 durableTerminal 回调断言。

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: ding113

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
Title check ✅ Passed 标题准确概括了对 provider-local model 404 进行故障切换的主要变更。
Description check ✅ Passed 描述直接说明了将特定 404 视为 Provider 本地能力缺口并继续切换/跳过重试,与改动一致。
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai
coderabbitai Bot requested a review from ding113 July 22, 2026 16:38

@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 `@src/app/v1/_lib/proxy/errors.ts`:
- Around line 580-585: Update isProviderLocalModelUnavailableError to reject
errors with statusCodeInferred set, and match the marker only against
error.message and error.upstreamError?.body, excluding rawBody. In
tests/unit/proxy/provider-local-model-unavailable.test.ts lines 61-71, replace
the rawBody-positive case with a regression asserting that statusCodeInferred:
true does not match.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8b9e9e6a-c860-4112-b1a6-aa878c5f57c9

📥 Commits

Reviewing files that changed from the base of the PR and between 30bdda8 and 3d65cba.

📒 Files selected for processing (5)
  • src/app/v1/_lib/proxy/errors.ts
  • src/app/v1/_lib/proxy/forwarder.ts
  • tests/unit/proxy/provider-local-model-unavailable.test.ts
  • tests/unit/proxy/proxy-forwarder-hedge-first-byte.test.ts
  • tests/unit/proxy/proxy-forwarder-retry-limit.test.ts

Comment thread src/app/v1/_lib/proxy/errors.ts

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d65cba22e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/app/v1/_lib/proxy/forwarder.ts Outdated

@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.

🧹 Nitpick comments (1)
src/app/v1/_lib/proxy/forwarder.ts (1)

78-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

使用 @/ 路径别名导入 errors

第 78 行仍使用相对路径 ./errors,违反 TypeScript 文件统一使用 @/ 映射 src/ 的规范。请改为 @/app/v1/_lib/proxy/errors

🤖 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 `@src/app/v1/_lib/proxy/forwarder.ts` at line 78, Update the errors import in
the forwarder module to use the `@/` alias, changing the relative ./errors
reference to `@/app/v1/_lib/proxy/errors` while preserving the existing imported
symbols.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@src/app/v1/_lib/proxy/forwarder.ts`:
- Line 78: Update the errors import in the forwarder module to use the `@/` alias,
changing the relative ./errors reference to `@/app/v1/_lib/proxy/errors` while
preserving the existing imported symbols.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 31cf8ec0-50c5-4b3a-9f5c-87cabed77e10

📥 Commits

Reviewing files that changed from the base of the PR and between 3d65cba and aa432c5.

📒 Files selected for processing (3)
  • src/app/v1/_lib/proxy/forwarder.ts
  • tests/unit/proxy/proxy-forwarder-hedge-first-byte.test.ts
  • tests/unit/proxy/proxy-forwarder-retry-limit.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/unit/proxy/proxy-forwarder-retry-limit.test.ts
  • tests/unit/proxy/proxy-forwarder-hedge-first-byte.test.ts

@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.

♻️ Duplicate comments (1)
src/app/v1/_lib/proxy/errors.ts (1)

581-587: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

不要使用 rawBody 进行错误规则匹配。

当前虽然排除了 statusCodeInferred === true,但后续仍把 upstreamError.rawBody 纳入 marker 检测。rawBody 的契约明确规定其仅用于响应返回,不参与规则匹配;否则当它与 message/body 不一致时,仍会误将错误分类为 RESOURCE_NOT_FOUND,进而改变故障转移行为。

建议修复
-  return [error.message, error.upstreamError?.body, error.upstreamError?.rawBody].some((content) =>
+  return [error.message, error.upstreamError?.body].some((content) =>
     content?.toLowerCase().includes(PROVIDER_LOCAL_MODEL_UNAVAILABLE_MARKER)
   );
🤖 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 `@src/app/v1/_lib/proxy/errors.ts` around lines 581 - 587, 更新 ProxyError 的 404
错误规则匹配逻辑,禁止将 upstreamError.rawBody 传入 marker 检测;仅使用契约允许参与匹配的 message/body
字段,并保留现有 statusCodeInferred 与 RESOURCE_NOT_FOUND 分类行为。
🤖 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.

Duplicate comments:
In `@src/app/v1/_lib/proxy/errors.ts`:
- Around line 581-587: 更新 ProxyError 的 404 错误规则匹配逻辑,禁止将 upstreamError.rawBody 传入
marker 检测;仅使用契约允许参与匹配的 message/body 字段,并保留现有 statusCodeInferred 与
RESOURCE_NOT_FOUND 分类行为。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bd98b0e6-16b1-4117-96a2-eb4f4dd3b8a5

📥 Commits

Reviewing files that changed from the base of the PR and between aa432c5 and f0a9ef1.

📒 Files selected for processing (2)
  • src/app/v1/_lib/proxy/errors.ts
  • tests/unit/proxy/provider-local-model-unavailable.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/proxy/provider-local-model-unavailable.test.ts

@Brisbanehuang

Copy link
Copy Markdown
Contributor Author

CI note after the latest push:

  • Integration Tests are now green; commit 73387e63 updates the two stale durableTerminal assertions for the existing deferred onCommitted callback.
  • The remaining Unit Tests / Test Summary failure is a base-branch failure, not introduced by this PR. dev run 29560439422 at the PR base SHA 30bdda8e fails the same 5 assertions in tests/unit/proxy/response-handler-endpoint-circuit-isolation.test.ts. The PR run has the same 5 failures, with the additional tests from this change passing.

Code Quality, API, Integration, Docker Build, CodeRabbit, and Greptile checks pass.

# Conflicts:
#	src/app/v1/_lib/proxy/errors.ts
#	src/app/v1/_lib/proxy/forwarder.ts
#	tests/unit/proxy/proxy-forwarder-retry-limit.test.ts
@ding113
ding113 merged commit 0f412f8 into ding113:dev Jul 22, 2026
9 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Claude Code Hub Roadmap Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants