Skip to content

XAI provider drops Authorization header — all Grok models fail with 'Missing Authentication header' (v7.0.3) #117

@teocns

Description

@teocns

Summary

On v7.0.3, every Grok model (grok-3, grok-4, grok-4.3, grok-4-fast-*, etc.) fails with Missing Authentication header from the proxy, despite XAI_API_KEY being correctly set in the environment. Direct calls to api.x.ai with the same key succeed, so the key itself is valid — claudish is not threading it onto the outbound request.

Environment

  • claudish version: 7.0.3 (/opt/homebrew/bin/claudish)
  • Platform: macOS (Darwin 25.2.0, arm64)
  • Auth state: XAI_API_KEY set (84 chars, no whitespace, validated). ANTHROPIC_API_KEY unset (OAuth login via Claude Code).

Reproduction

export XAI_API_KEY=xai-...   # valid key
claudish --model grok-3 -p "hi"

Output:

[claudish] Model: grok-3
[Auto-route] Auto-routed: grok-3 -> xai (api-key)
[Auto-route] Auto-routed: grok-3 -> xai (api-key)   # fires repeatedly (retry loop)
...

Probe confirms the failure:

$ claudish --probe grok-3
┌─ grok-3 ──────────────────────────────── xai · 0/1 live ─┐
│  1 │ xAI │ xai@grok-3 │ ⊗ auth 401                       │
│      └ Missing Authentication header                     │

Proxy log (~/.claudish/logs/...):

[Proxy] Server started on port 4690
[Auto-route] Auto-routed: grok-3 -> xai (api-key)
{"type":"error","error":{"type":"authentication_error","message":"invalid x-api-key"},"request_id":"req_011CamQ..."}

Evidence the bug is on claudish's side, not XAI's

  1. Direct curl with the same key works:

    curl https://api.x.ai/v1/chat/completions \
      -H "Authorization: Bearer $XAI_API_KEY" \
      -d '{"model":"grok-3","messages":[{"role":"user","content":"hi"}]}'
    # → 200 OK, valid response
  2. XAI's actual error vocabulary differs. When Authorization header is missing or empty, api.x.ai returns:

    {"code":"...","error":"No credentials presented. [WKE=unauthenticated:no-credentials]"}

    not "Missing Authentication header". The string "Missing Authentication header" does not appear in claudish's strings output and is not in XAI's error wording — it appears to be generated internally inside the bundled JS when key resolution returns empty.

  3. Provider config in the binary is correct:

    name: "xai"
    transport: "openai"
    baseUrl: "https://api.x.ai"
    apiPath: "/v1/chat/completions"
    apiKeyEnvVar: "XAI_API_KEY"
    

    Default authScheme for the openai transport is "bearer" (also confirmed in strings).

  4. Workarounds tried, all fail with the same error:

    • Bare --model grok-3 → routes to xai, fails
    • Explicit --model xai@grok-3 → routes to OpenRouter (wrong) → 401 Missing OPENROUTER_API_KEY
    • Explicit --model x-ai@grok-3 → same OpenRouter fallthrough
    • Adding apiKeys.XAI_API_KEY to ~/.claudish/config.json → no effect
    • Defining XAI as a customEndpoints entry with explicit apiKey field → still Missing Authentication header

Likely root cause

The OpenAIProviderTransport (or its key-resolution helper) is not reading process.env[provider.apiKeyEnvVar] at request time for the XAI provider. The auto-router can read XAI_API_KEY (the Auto-routed: ... -> xai (api-key) log line proves it sees the key for routing decisions), but the request-builder code path drops it before constructing the outbound Authorization header. Other providers using the same transport: "openai" (e.g. openai, glm) appear to work, so the bug may be specific to how XAI's provider entry is wired into the transport — possibly a missing authScheme: "bearer" field on the provider config (other openai-transport providers like openrouter declare it explicitly).

Suggested fix

Either (a) ensure the OpenAIProviderTransport always falls back to process.env[provider.apiKeyEnvVar] when the resolved key is empty, or (b) explicitly set authScheme: "bearer" on the XAI provider entry alongside the existing transport: "openai".

Impact

All XAI/Grok routing is currently non-functional in v7.0.3 with environment-variable auth, which is the documented setup path. Users hit a confusing error message that points at credentials when the credentials are correct.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions