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

  1. Ensure x-goog-api-key and any key/$key query parameter carry the identical API key, or remove one of them
  2. Strip stale ?key=... query parameters from upstream URLs before forwarding
  3. Check client SDK configuration for double credential injection (header plus query)
  4. 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

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


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" {
			continue

View on GitHub (pinned to 3ee70a1026)