Repository navigation
fix(antigravity): classify geo-blocked egress, exclude account, real connection probe - #10420
Conversation
…connection probe Google refuses the Cloud Code model API from unsupported egress locations with 400 FAILED_PRECONDITION "User location is not supported for the API use." Previously this surfaced as a cryptic "Antigravity upstream error (400)", never excluded the account, and the dashboard connection test stayed green because it only probed the (non-geo-restricted) OAuth userinfo endpoint. - errorClassifier: new GEO_BLOCKED type + isGeoBlockedError detection (400/403 + location-not-supported wording); non-terminal classification. - chatCore fallback: GEO_BLOCKED marks the connection and caches a 24h rate-limit-until exclusion so routing moves to other accounts instead of re-selecting the same one; never bans/expires the account. - auth: GEO_BLOCKED joins the non-terminal group (no banned/expired state). - antigravityUpstreamError: geo refusals carry an actionable message (egress location vs account problem, proxy-in-supported-region guidance). - connection test: antigravity/agy now probe the REAL streamGenerateContent surface (buildProbe), so a green tick means the model path actually works and a geo-blocked egress shows red with a clear diagnosis.
…o-block resilience
The earlier format pass (local prettier differs from the repo's pinned version) rewrapped unrelated lines in chatCore.ts and the provider test route. Restore the base formatting and re-apply only the GEO_BLOCKED fallback branch and the buildProbe connection-test changes.
…EXHAUSTED)
Port decolua/9router b566b20, generalized: Antigravity flags system prompts
advertising competing agents ('You are a Claude agent, built on Anthropic's
Claude Agent SDK.' — Zed, Claude Code, etc.) and answers with a 429 quota
error. sanitizeAntigravityGeminiRequest now strips known competitor identity
sentences from systemInstruction.parts before dispatch; surrounding
instruction text is untouched and non-matching prompts pass through without
allocation.
…avity-geoblock-resilience
…avity-geoblock-resilience
…avity-geoblock-resilience
… (#geoblock-resiliencefix/antigravity-geoblock-resilience)
|
Thanks for the deep dive here — the root-cause framing (green tick only proving the OAuth userinfo probe works, not the actual model path) is exactly right, and the fix is a clean, minimal extension of the existing non-terminal connection-cooldown pattern (mirrors PROJECT_ROUTE_ERROR almost 1:1 across errorClassifier.ts/chatCore.ts/auth.ts). I checked this out locally against release/v3.8.50 tip and ran the suite:
This is merge-ready as-is. Two things I'd love a quick take on, neither blocking:
Nice work — appreciate the actionable error messages and the reviewer notes explaining the Toronto-proxy repro. |
…avity-geoblock-resilience
Address reviewer feedback: classifyProviderError is shared across every provider, so a lookalike 'not available in your region' body from an unrelated upstream must not receive the egress-fixable 24h exclusion treatment. Gate GEO_BLOCKED behind isGeoBlockEligibleProvider, which matches the surfaces that actually emit Google's regional-availability refusal: Cloud Code / Gemini Code Assist (antigravity, agy, cloudcode*), the Gemini Developer API (gemini, gemini-cli, vertex), plus a registry-driven fallback on executor/format. Non-Google providers fall through to their existing 400/403 classification (typically null for an unclassified 400), so a permanent block still follows its own path.
|
Thanks for the close read — both points are fair, and point 1 is now fixed on the branch (bfd06e9).
|
Trigger a fresh CI run for the PR: the previous run's 'Vitest (fast-path)' job failed in 'npm ci' because the onnxruntime-node postinstall could not download its binary from the Microsoft CDN (connect ETIMEDOUT 150.171.109.118:443). No tests ran; no code changed in this commit.
|
Re-triggered CI with an empty commit (c727e77): the previous Quality Gates run's "Vitest (fast-path)" job failed during |
…gate isGeoBlockEligibleProvider passes the raw provider (string | null | undefined) to getRegistryEntry(provider: string), failing typecheck:core and the ts7-diagnostics ratchet (TS2345 at errorClassifier.ts:166). Add an explicit null guard; runtime behavior is unchanged — a falsy provider already resolved to !entry -> false.
…avity-geoblock-resilience
…avity-geoblock-resilience
…avity-geoblock-resilience
…avity-geoblock-resilience
e44a409
into
cheaper-inference:release/v3.8.50
|
Validated in local merge-train |
…connection probe (cheaper-inference#10420) * fix(antigravity): classify geo-blocked egress, exclude account, real connection probe Google refuses the Cloud Code model API from unsupported egress locations with 400 FAILED_PRECONDITION "User location is not supported for the API use." Previously this surfaced as a cryptic "Antigravity upstream error (400)", never excluded the account, and the dashboard connection test stayed green because it only probed the (non-geo-restricted) OAuth userinfo endpoint. - errorClassifier: new GEO_BLOCKED type + isGeoBlockedError detection (400/403 + location-not-supported wording); non-terminal classification. - chatCore fallback: GEO_BLOCKED marks the connection and caches a 24h rate-limit-until exclusion so routing moves to other accounts instead of re-selecting the same one; never bans/expires the account. - auth: GEO_BLOCKED joins the non-terminal group (no banned/expired state). - antigravityUpstreamError: geo refusals carry an actionable message (egress location vs account problem, proxy-in-supported-region guidance). - connection test: antigravity/agy now probe the REAL streamGenerateContent surface (buildProbe), so a green tick means the model path actually works and a geo-blocked egress shows red with a clear diagnosis. * chore(changelog): fragment for cheaper-inference#10420 antigravity geo-block resilience * chore(pr): drop prettier-version drift noise, keep only real hunks The earlier format pass (local prettier differs from the repo's pinned version) rewrapped unrelated lines in chatCore.ts and the provider test route. Restore the base formatting and re-apply only the GEO_BLOCKED fallback branch and the buildProbe connection-test changes. * fix(antigravity): strip competing-agent system prompts (429 RESOURCE_EXHAUSTED) Port decolua/9router b566b20, generalized: Antigravity flags system prompts advertising competing agents ('You are a Claude agent, built on Anthropic's Claude Agent SDK.' — Zed, Claude Code, etc.) and answers with a 429 quota error. sanitizeAntigravityGeminiRequest now strips known competitor identity sentences from systemInstruction.parts before dispatch; surrounding instruction text is untouched and non-matching prompts pass through without allocation. * chore(changelog): cover competitive prompt strip in cheaper-inference#10420 fragment * fix(antigravity): scope GEO_BLOCKED classification to Google AI surfaces Address reviewer feedback: classifyProviderError is shared across every provider, so a lookalike 'not available in your region' body from an unrelated upstream must not receive the egress-fixable 24h exclusion treatment. Gate GEO_BLOCKED behind isGeoBlockEligibleProvider, which matches the surfaces that actually emit Google's regional-availability refusal: Cloud Code / Gemini Code Assist (antigravity, agy, cloudcode*), the Gemini Developer API (gemini, gemini-cli, vertex), plus a registry-driven fallback on executor/format. Non-Google providers fall through to their existing 400/403 classification (typically null for an unclassified 400), so a permanent block still follows its own path. * ci: re-run quality gates Trigger a fresh CI run for the PR: the previous run's 'Vitest (fast-path)' job failed in 'npm ci' because the onnxruntime-node postinstall could not download its binary from the Microsoft CDN (connect ETIMEDOUT 150.171.109.118:443). No tests ran; no code changed in this commit. * fix(antigravity): guard provider before registry lookup in geo-block gate isGeoBlockEligibleProvider passes the raw provider (string | null | undefined) to getRegistryEntry(provider: string), failing typecheck:core and the ts7-diagnostics ratchet (TS2345 at errorClassifier.ts:166). Add an explicit null guard; runtime behavior is unchanged — a falsy provider already resolved to !entry -> false. * ci: re-run quality gates (vitest npm ci onnxruntime CDN flake) --------- Co-authored-by: Rouzbeh <rqzbeh@users.noreply.github.com>
…connection probe (cheaper-inference#10420) * fix(antigravity): classify geo-blocked egress, exclude account, real connection probe Google refuses the Cloud Code model API from unsupported egress locations with 400 FAILED_PRECONDITION "User location is not supported for the API use." Previously this surfaced as a cryptic "Antigravity upstream error (400)", never excluded the account, and the dashboard connection test stayed green because it only probed the (non-geo-restricted) OAuth userinfo endpoint. - errorClassifier: new GEO_BLOCKED type + isGeoBlockedError detection (400/403 + location-not-supported wording); non-terminal classification. - chatCore fallback: GEO_BLOCKED marks the connection and caches a 24h rate-limit-until exclusion so routing moves to other accounts instead of re-selecting the same one; never bans/expires the account. - auth: GEO_BLOCKED joins the non-terminal group (no banned/expired state). - antigravityUpstreamError: geo refusals carry an actionable message (egress location vs account problem, proxy-in-supported-region guidance). - connection test: antigravity/agy now probe the REAL streamGenerateContent surface (buildProbe), so a green tick means the model path actually works and a geo-blocked egress shows red with a clear diagnosis. * chore(changelog): fragment for cheaper-inference#10420 antigravity geo-block resilience * chore(pr): drop prettier-version drift noise, keep only real hunks The earlier format pass (local prettier differs from the repo's pinned version) rewrapped unrelated lines in chatCore.ts and the provider test route. Restore the base formatting and re-apply only the GEO_BLOCKED fallback branch and the buildProbe connection-test changes. * fix(antigravity): strip competing-agent system prompts (429 RESOURCE_EXHAUSTED) Port decolua/9router b566b20, generalized: Antigravity flags system prompts advertising competing agents ('You are a Claude agent, built on Anthropic's Claude Agent SDK.' — Zed, Claude Code, etc.) and answers with a 429 quota error. sanitizeAntigravityGeminiRequest now strips known competitor identity sentences from systemInstruction.parts before dispatch; surrounding instruction text is untouched and non-matching prompts pass through without allocation. * chore(changelog): cover competitive prompt strip in cheaper-inference#10420 fragment * fix(antigravity): scope GEO_BLOCKED classification to Google AI surfaces Address reviewer feedback: classifyProviderError is shared across every provider, so a lookalike 'not available in your region' body from an unrelated upstream must not receive the egress-fixable 24h exclusion treatment. Gate GEO_BLOCKED behind isGeoBlockEligibleProvider, which matches the surfaces that actually emit Google's regional-availability refusal: Cloud Code / Gemini Code Assist (antigravity, agy, cloudcode*), the Gemini Developer API (gemini, gemini-cli, vertex), plus a registry-driven fallback on executor/format. Non-Google providers fall through to their existing 400/403 classification (typically null for an unclassified 400), so a permanent block still follows its own path. * ci: re-run quality gates Trigger a fresh CI run for the PR: the previous run's 'Vitest (fast-path)' job failed in 'npm ci' because the onnxruntime-node postinstall could not download its binary from the Microsoft CDN (connect ETIMEDOUT 150.171.109.118:443). No tests ran; no code changed in this commit. * fix(antigravity): guard provider before registry lookup in geo-block gate isGeoBlockEligibleProvider passes the raw provider (string | null | undefined) to getRegistryEntry(provider: string), failing typecheck:core and the ts7-diagnostics ratchet (TS2345 at errorClassifier.ts:166). Add an explicit null guard; runtime behavior is unchanged — a falsy provider already resolved to !entry -> false. * ci: re-run quality gates (vitest npm ci onnxruntime CDN flake) --------- Co-authored-by: Rouzbeh <rqzbeh@users.noreply.github.com>
Summary
Antigravity / Gemini Code Assist models (gemini-3.6-flash, etc.) fail from this
class of deployment with 400 FAILED_PRECONDITION "User location is not
supported for the API use." — Google refuses the Cloud Code model API
(
daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent) fromunsupported egress locations. The dashboard "Test Connection" stayed green
because it only probed the OAuth userinfo endpoint
(
googleapis.com/oauth2/v1/userinfo), which is NOT geo-restricted — so a greentick never proved the model path worked.
This PR fixes three things:
GEO_BLOCKEDprovider error (open-sse/services/errorClassifier.ts),instead of falling through as a generic 400.
with a 24h
rate_limited_untilexclusion (open-sse/handlers/chatCore.ts),so routing moves to other accounts instead of re-selecting the broken one on
every request. It is non-terminal (never banned/expired —
src/sse/services/auth.ts),so the account recovers automatically once egress is fixed.
REAL model surface (
streamGenerateContentwith a 1-token body, mirroring theexecutor's URL/headers), so a green tick means the model path actually works
and a geo-blocked egress shows red with an actionable diagnosis.
Error messages now explain the real cause (egress location vs account problem)
and the remedy (route antigravity/agy egress through a proxy in a supported
region, e.g. US/EU) instead of "Antigravity upstream error (400)".
Related Issues
Validation
npm run lint— no issues in changed files (repo-wide baseline haspre-existing errors in unrelated dashboard files; local install used
--no-package-lockdue to lockfile drift on the release branch)Focused tests run:
Tests Added Or Updated
tests/unit/antigravity-geoblock-resilience.test.ts(new):generic 400 not classified as geo; 429 unaffected
established repo behavior against regression)
non-geo body unchanged
v1internal:streamGenerateContentwith a minimal body (not userinfo)Coverage Notes
open-sse/services/errorClassifier.ts,open-sse/handlers/chatCore.ts,open-sse/config/errorConfig.ts,open-sse/executors/antigravityUpstreamError.ts,src/sse/services/auth.ts,and the connection-test route (
src/app/api/providers/[id]/test/{route,oauthTestConfig}.ts).probe construction; the chatCore exclusion branch follows the existing
PROJECT_ROUTE_ERROR pattern (connection state write is best-effort).
Reviewer Notes
rate_limited_until(24h viaCOOLDOWN_MS.geoBlocked) because the account-selection layer already honorsit; the connection's
lastErrorType/lastError/errorCoderecord the realreason for the dashboard.
buildProbeis a new optional OAuth-test-config hook; the codex-styleacceptStatusessemantics are unchanged, and the 401/403 refresh-retry pathnow reuses the built probe when present.
treats Google's "Resource has been exhausted (e.g. queries per minute...)"
as a per-minute rate limit (rate_limited), which is correct.
currently exits in Toronto, CA — Google does not offer this API from Canada.
Point antigravity/agy egress at a proxy in a supported region (e.g. US/EU)
and the accounts become usable without re-adding them.
Competitive system-prompt strip (follow-up commit)
Antigravity's server-side filter flags system prompts advertising competing
agents ("You are a Claude agent, built on Anthropic's Claude Agent SDK." —
Zed, Claude Code, etc.) and answers with 429 RESOURCE_EXHAUSTED.
sanitizeAntigravityGeminiRequestnow strips known competitor identitysentences from
systemInstruction.partsbefore dispatch (port ofdecolua/9router b566b20, generalized). Surrounding instruction text is
untouched; non-matching prompts pass through without allocation.
Tests:
tests/unit/antigravity-competitive-prompt-strip.test.ts(6 cases) —all green alongside the geo-block suite (50/50).