Skip to content

Fix TUI Grok subscription rejected with credit-limit error despite "(key connected)" - #14774

Open
warp-agent-staging[bot] wants to merge 2 commits into
masterfrom
factory/quality-1508-grok-sub-key-connected
Open

Fix TUI Grok subscription rejected with credit-limit error despite "(key connected)"#14774
warp-agent-staging[bot] wants to merge 2 commits into
masterfrom
factory/quality-1508-grok-sub-key-connected

Conversation

@warp-agent-staging

@warp-agent-staging warp-agent-staging Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

With a connected X Premium / SuperGrok subscription, grok * models in the TUI model picker render (key connected), but sending a request is rejected with the Warp credit-limit error ("You've reached your credit limit…"). QUALITY-1508.

Root cause: the picker's (key connected) suffix for xAI comes from is_using_api_key_for_provider (app/src/ai/llms.rs), which checked the loose manager.grok_tokens().is_some(). But the request-time token attach (GrokTokens::access_token_for_request) and the credit-availability gate (has_usable_byo_inference_pathApiKeyManager::has_any_keyhas_grok_subscription) both require a usable (non-blank) OAuth access token. A stored Grok token whose access token is blank therefore rendered as (key connected) while nothing was sent on the wire and the credit gate treated the subscription as absent — the server then fell through to the Warp credit gate and rejected, exactly as reported.

Fix: single-source the xAI "usable Grok subscription" predicate on has_grok_subscription() so the picker, the request-time attach, and the credit gate all agree. This makes it impossible for (key connected) to appear while the credit/inference path treats the subscription as absent (acceptance criterion #2). The credit-availability decision already recognizes a connected Grok subscription (via has_any_key()), and the request-time attach gates the token on the same BYO policy, so no change was needed there; this change removes the remaining inconsistency.

Scope note (possible warp-server component — not changed)

Triage flagged a possible server-side cause (the server stripping GrokOauthAccessToken when CanUseByoKey is false). Reviewing the client wire path, the client attaches the Grok token whenever BYO keys are enabled and the token is usable, and the credit gate already honors a connected subscription — so the confirmed, reproducible-in-code defect is client-side. The server-strip hypothesis remains unproven and is out of scope for this PR; per the ticket it hinges on the reporter's wire data, which isn't available here. No warp-server change is opened on speculation.

Verification

  • Regression test (fails before / passes after): xai_key_connected_requires_usable_grok_access_token in app/src/ai/llms_tests.rs — asserts is_using_api_key_for_provider(&LLMProvider::Xai, …) is false for a connected GrokTokens with a blank access token and true for a usable one (with BYO enabled). Verified it FAILS against the pre-fix predicate and PASSES with the fix.
  • Coverage guard: test_out_of_credits_refined_by_connected_grok_subscription in app/src/ai/request_usage_model_tests.rs — under a server OutOfCredits decision, a connected Grok subscription permits AI, a blank token does not, and BYO/Bedrock refinement is unaffected (acceptance criteria Search history by more than just command #1 and Shared environment variables and secrets #3).
  • Touched-package suite: cargo nextest run -p warp -E 'test(request_usage_model) + test(llms) + test(prompt_alert)' → 91 passed.
  • cargo fmt -p warp (clean) and cargo clippy -p warp --all-targets --tests -- -D warnings (clean).

Visual proof not obtainable

This touches a user-facing TUI surface (the model picker suffix and the agent error state), but a live repro needs a logged-in account with a connected SuperGrok OAuth subscription in an out-of-Warp-credits state against a live server — production-only credentials/infra not available in this environment. Per the ticket, hands-on visual proof is deferred; the behavior is covered by the deterministic tests above.

CHANGELOG-BUG-FIX: Fix Grok subscription models in the TUI showing "(key connected)" but being rejected with the Warp credit-limit error
Originating thread: https://warpdev.slack.com/archives/C0BDQDW8V5E/p1785983338928669

This PR was generated with Oz.

The model picker's "(key connected)" suffix for xAI came from
`is_using_api_key_for_provider`, which checked the loose
`grok_tokens().is_some()`. The request-time token attach
(`GrokTokens::access_token_for_request`) and the credit-availability gate
(`has_usable_byo_inference_path` -> `ApiKeyManager::has_any_key` ->
`has_grok_subscription`) both require a *usable* (non-blank) access token.

A stored Grok token with a blank access token therefore rendered as
"(key connected)" while nothing was sent on the wire and the credit gate
treated the subscription as absent, producing the reported Warp
credit-limit rejection despite the picker promising a connected key.

Single-source the xAI predicate on `has_grok_subscription()` so the
picker, the request attach, and the credit gate all agree.

Co-Authored-By: Warp <agent@warp.dev>
@cla-bot cla-bot Bot added the cla-signed label Aug 6, 2026
@warp-agent-staging warp-agent-staging Bot added the warpy-factory Label associated to the "Wob the Wuilder" factory on staging, also known as Warpy Factory. label Aug 6, 2026
@warp-agent-staging
warp-agent-staging Bot marked this pull request as ready for review August 6, 2026 03:11
@warp-agent-staging
warp-agent-staging Bot requested a review from jefflloyd August 6, 2026 03:11

@warp-agent-staging warp-agent-staging Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Overview

This PR single-sources the xAI (key connected) predicate on has_grok_subscription() so the model picker can't claim a usable Grok subscription while the credit gate treats it as absent (acceptance criterion #2); the change itself is correct, minimal, and well-tested. Requesting changes: the required Formatting + Clippy CI job is red, and there's an open question about whether this client-only fix actually resolves the reporter's server-originated symptom.

Concerns

❓ [QUESTION] @jefflloyd — the reported failure was a server-originated out-of-credits error, so the request reached the server with no usable Grok token on the wire; this change makes (key connected) honest and the credit gate (has_any_keyhas_grok_subscription) already honors a usable subscription, which fully covers cause #1 (a blank local token over-promising in the picker) but not cause #2 (server strips GrokOauthAccessToken when CanUseByoKey is false) or cause #3 (cross-process reload_keys_from_secure_storage never re-reads Grok tokens). Under cause #2 the picker would still show (key connected) for a usable token and the server would still reject, so the reporter's symptom could persist. Since disambiguating needs the reporter's wire data / a production SuperGrok account (unavailable to the agent), can you — as the REV-1714 author — confirm which cause matches the report before merge, so we know this resolves the reporter's issue rather than only aligning the picker label?

A blocking implementation-addressable finding (the failing Formatting + Clippy CI job — an import-ordering diff in app/src/ai/llms_tests.rs, fixed by running ./script/format) is being relayed to implementation automatically for rework.

Verdict

Checks: fmt ❌ (import-ordering diff in app/src/ai/llms_tests.rs, reproduced via ./script/format --check) · CI ❌ (Formatting + Clippy failing on Linux/MacOS/Windows) · build/tests not run locally (heavy crate; CI is the backstop) · visual proof n/a (documented production-only SuperGrok + out-of-credits repro; picker/credit-gate behavior covered by unit tests)
Found: 1 critical, 0 important, 0 suggestions, 1 open question

Request changes

Review run

https://oz.staging.warp.dev/runs/019fd510-44f2-7c46-a3b4-11f4d6ee94ce

The added MockTelemetryContextProvider import must sit in the single
external-crate group (group_imports=StdExternalCrate), sorted before
`warpui::App` with no separating blank line. Applied via ./script/format.

Co-Authored-By: Warp <agent@warp.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed warpy-factory Label associated to the "Wob the Wuilder" factory on staging, also known as Warpy Factory.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant