JuliusBrussee/caveman · error
ErrGoogleRequestCredentials
ErrGoogleRequestCredentials
Error message
Google request credentials are invalid or conflicting
What it means
Google requests support exactly one credential spelling set: the x-goog-api-key header and key/$key system parameters. ErrGoogleRequestCredentials is a value-free sentinel returned when those equivalent inputs disagree or one is malformed, and the gateway maps it to HTTP 400 with code 'cave_provider_credentials_conflict'.
Solutions
- Ensure x-goog-api-key and any key/$key query parameter carry the identical API key, or remove one of them
- Strip stale ?key=... query parameters from upstream URLs before forwarding
- Check client SDK configuration for double credential injection (header plus query)
- Replace the API key if it is malformed (Google keys are typically AIza... strings)
Example fix
// before (conflicting) curl -H "x-goog-api-key: KEY_A" "https://.../v1/models?key=KEY_B" // after # drop the query param curl -H "x-goog-api-key: KEY_A" "https://.../v1/models"
Defensive patterns
Strategy: validation
Validate before calling
if h := r.Header.Get("x-goog-api-key"); h != "" && r.URL.Query().Get("key") != "" && h != r.URL.Query().Get("key") {
// conflict: strip or reconcile before sending
}
Try / catch
upstreamURL, err := adapter.ResolveUpstreamURL(ctx, r, providers.RouteContext{})
if err != nil {
if errors.Is(err, providers.ErrGoogleRequestCredentials) {
httpx.Error(w, r, http.StatusBadRequest, "cave_provider_credentials_conflict", err.Error())
return
}
}
Prevention
- Use one Google credential spelling per request (header or query, not both)
- Strip ?key= params when a client already sends x-goog-api-key
- Audit proxied client configs for double credential injection
When it happens
Trigger: ResolveUpstreamURL / header sanitization see x-goog-api-key and a ?key= (or $key) parameter carrying different values, a malformed key, or otherwise conflicting Google auth inputs on the same request.
Common situations: SDK clients that inject an API key header while the URL was built with a ?key= query param holding an older key; proxying clients configured for two different Google projects; leftover query params from copied example URLs.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- cannot safely resolve Qwen's effective OPENAI_API_KEY
- Expected a Google Client and synchronous MiddlewareRuntime
- Expected a native Google Chat or AsyncChat
- Install caveman-middleware[google] to use the Google adapter
- managed Bedrock wrap requires a valid CAVE_API_KEY
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/0ccbaad9f1e436a4.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/providers/google_credentials.go:12
package providers
import (
"errors"
"net/http"
"net/url"
"strings"
)
// ErrGoogleRequestCredentials contains no caller values and is safe to return
// when equivalent Google authentication inputs disagree or are malformed.
var ErrGoogleRequestCredentials = errors.New("Google request credentials are invalid or conflicting")
// GoogleRequestAPIKey resolves the credential spellings Google documents: the
// x-goog-api-key header and the key/$key system parameters. Nothing else counts
// as a Google credential — in particular x-api-key is another provider's header,
// so it neither conflicts with these nor selects a Google account here.
//
// https://cloud.google.com/apis/docs/system-parameters
// https://ai.google.dev/gemini-api/docs/api-key
func GoogleRequestAPIKey(req *http.Request) (string, error) {
key := strings.TrimSpace(req.Header.Get("x-goog-api-key"))
if strings.ContainsAny(key, "\r\n") {
return "", ErrGoogleRequestCredentials
}
for _, part := range strings.Split(req.URL.RawQuery, "&") {
name, value, _ := strings.Cut(part, "=")
name, _ = url.QueryUnescape(name)
if name != "key" && name != "$key" {
continueView on GitHub (pinned to 3ee70a1026)