Skip to content

fix(auth): unblock [M] manual-fallback API key path + suppress misleading "Claude model unavailable" error#867

Draft
bird-m wants to merge 2 commits into
mainfrom
cursor/fix-manual-fallback-api-key-flow-b126
Draft

fix(auth): unblock [M] manual-fallback API key path + suppress misleading "Claude model unavailable" error#867
bird-m wants to merge 2 commits into
mainfrom
cursor/fix-manual-fallback-api-key-flow-b126

Conversation

@bird-m

@bird-m bird-m commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Two regressions, both reported in #npx-amplitude-wizard:

  1. "When I manually paste in my API key from my account, nothing happens."
  2. "Then I asked the Wizard if something broke, and I got a Claude error in return." (There's an issue with the selected model (anthropic/claude-sonnet-4-6). It may not exist or you may not have access to it. Run --model to pick a different model.)

Both surfaced after the browser sign-in returned 400 Bad Request — Request Header Or Cookie Too Large from auth.amplitude.com (Colin's workaround: clear AMP_*** cookies — pre-existing cookies push the PKCE-laden URL past nginx's large_client_header_buffers budget). With OAuth blocked, the user pressed [M] to enter their API key directly — and ran straight into the two regressions below.

Symptom 1 — silent manual-fallback submission

AuthScreen.tsx's handleApiKeySubmit set credentials and persisted the key, but:

  • manualFallbackOpen stayed true, so the screen kept rendering the same Enter your project API key headline + an empty TextInput.
  • The savedKeySource ✓ row only renders in Step 5 (api_key_notice path), not in the [M] view.

Net effect: the user saw zero acknowledgement of their action and reasonably assumed the wizard was hung.

Fix: after a successful submit, close the fallback form (setManualFallbackOpen(false)) and surface a green checkmark line in the OAuth-waiting view above the login URL:

✓ API key saved — finish browser sign-in to continue.

Note: the [M] path can't on its own satisfy Auth.isComplete (that gate also needs a resolved org/project, which only browser OAuth supplies). So we can't advance the flow on the strength of the key alone — but we can give the user a visible "received" signal and tell them what they still need to do.

Symptom 2 — Tab/Ask routes to a confusing "Claude model unavailable" error

resolveConsoleCredentials in src/lib/console-query.ts returned kind: 'gateway' as long as the session had a projectApiKey + host, even when credentials.accessToken === '' (the [M] path has no OAuth bearer yet). queryConsole then routed through queryConsoleWithClaudeAgentSdkinitializeAgent, which falls through to the local-claude CLI path:

const useLocalClaude = !config.amplitudeBearerToken && !useDirectApiKey;

The Claude Code SDK then surfaced the misleading There's an issue with the selected model (anthropic/claude-sonnet-4-6)... error — totally orthogonal to what was actually wrong (the user wasn't authenticated).

Fix: require a non-empty credentials.accessToken for the gateway branch. When that's missing, fall through to kind: 'none' so queryConsole's existing early-exit surfaces the friendly:

Claude is not available yet — complete authentication first.

Test plan

  • New focused tests:
    • src/lib/__tests__/console-query.test.ts — two regression cases pinning the accessToken-empty path to kind: 'none' and the populated path to kind: 'gateway'.
    • src/ui/tui/screens/__tests__/AuthScreen.manual-fallback.test.tsx — drives the full keystroke path (M → 32-char hex key → Enter) and asserts both the credential mutation and the acknowledgement copy.
  • Ran related Vitest paths in stable forks pool (per CLAUDE.md):
pnpm exec vitest run --pool=forks --maxWorkers=1 \
  src/ui/tui/screens/__tests__/AuthScreen.region-host.test.tsx \
  src/ui/tui/screens/__tests__/AuthScreen.snap.test.tsx \
  src/ui/tui/screens/__tests__/AuthScreen.coaching.test.tsx \
  src/ui/tui/screens/__tests__/AuthScreen.manual-fallback.test.tsx \
  src/lib/__tests__/console-query.test.ts \
  src/ui/tui/__tests__/router.test.ts \
  src/ui/tui/__tests__/flow-invariants.test.ts
# → Test Files  7 passed (7)
# → Tests       178 passed (178)
  • pnpm exec prettier --check and pnpm exec eslint clean on all four touched files; lint-staged hooks ran on each commit.

Out of scope / follow-ups

  • The underlying 400 Request Header Or Cookie Too Large from auth.amplitude.com is a server-side nginx / cookie-budget issue, not a wizard bug. Not addressed here.
  • The [M] fallback still can't, by design, complete a full wizard run without OAuth (no org/project resolution). The acknowledgement copy now tells the user that explicitly. A bigger product decision to allow API-key-only runs would touch Auth.isComplete, several downstream screens, and analytics scoping — tracked separately.

Checklist

  • Opened PR via the cloud-agent PR tool after push.
  • pnpm exec prettier --check and pnpm exec eslint pass on all changed files; targeted Vitest runs green (see above).
  • TUI / router / flows.ts / store.ts navigation: ran the focused Vitest commands from CLAUDE.md on router.test.ts + flow-invariants.test.ts + the relevant screens/__tests__/ files.
  • No /reflect checklist needed — narrow surgical bug fix, no architectural drift.
  • No LLM call-site IDs added, removed, or changed — queryConsole semantics (gateway / direct / none) are preserved; only the gating predicate was tightened.

Slack Thread

Open in Web Open in Cursor 

…-296)

When the OAuth browser redirect fails (e.g. 'Request Header Or Cookie Too Large'
from auth.amplitude.com nginx due to large AMP_*** cookies), users press [M] on
the AuthScreen to enter their project API key manually. Two regressions made
that path looked broken:

1. AuthScreen never closed the manual-fallback form after submit, and the
   OAuth-waiting view didn't surface any 'API key saved' acknowledgement —
   so the user saw the same 'Enter your project API key' headline + empty
   input field after pressing Enter and concluded the wizard was hung
   ('nothing happens after pasting'). Addressed in a sibling commit on
   AuthScreen.tsx.

2. resolveConsoleCredentials returned 'kind: gateway' as long as the session
   had a projectApiKey + host, even when credentials.accessToken was empty
   (the M-fallback path has no OAuth bearer yet). queryConsole would then
   route through queryConsoleWithClaudeAgentSdk → initializeAgent, which
   falls through to the local-claude CLI path
   (useLocalClaude = !bearerToken && !ANTHROPIC_API_KEY). The Claude Code
   SDK then surfaced 'There's an issue with the selected model
   (anthropic/claude-sonnet-4-6). It may not exist or you may not have
   access to it. Run --model to pick a different model.' — totally
   misleading for an unauthenticated user. Guard the gate so the user
   instead sees the friendly 'Claude is not available yet — complete
   authentication first.' surfaced by queryConsole's existing 'none'
   branch.
… line after submission (BA-296)

Pre-fix repro:
  1. User on AuthScreen OAuth-waiting view, browser tab returns 400 from
     auth.amplitude.com (oversized cookies).
  2. User presses [M], pastes their project API key, hits Enter.
  3. handleApiKeySubmit fires, setCredentials/persistApiKey succeed, but
     manualFallbackOpen stays true and savedKeySource is only rendered
     in Step 5 (api_key_notice path) — not in the [M] view.
  4. The frame is unchanged: same 'Enter your project API key' headline,
     same empty TextInput, no acknowledgement anywhere.
  5. User assumes the wizard is broken ('nothing happens after pasting').

Note: the M-fallback path can't on its own satisfy Auth.isComplete —
that gate also needs a resolved org/project tuple, which only browser
OAuth (or stored creds) supplies. So we can't advance the flow on the
strength of the key alone. But we can — and now do — give the user a
visible 'received' signal and tell them what they still need to do.

After this commit:
  - handleApiKeySubmit calls setManualFallbackOpen(false) so the
    OAuth-waiting view re-renders.
  - That view now surfaces a green checkmark line:
      ✓ API key saved — finish browser sign-in to continue.
    above the login URL so the user understands their action landed
    and what the next step is.

Added a focused render test
(src/ui/tui/screens/__tests__/AuthScreen.manual-fallback.test.tsx) that
walks the full keystroke path (M → 32-char hex key → Enter) and
asserts both the credential mutation and the acknowledgement copy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants