Skip to content

google-vertex ADC broken: '<authenticated>' marker passed as apiKey to @google/genai SDK #48033

@seperman-dev

Description

@seperman-dev

Bug Description

Google Vertex AI with Application Default Credentials (ADC) fails with 401 UNAUTHENTICATED since OpenClaw 2026.3.13 / pi-ai 0.58.0 / @google/genai 1.45.0.

The <authenticated> sentinel value returned by pi-ai's getEnvApiKey("google-vertex") is passed as a literal API key to the @google/genai SDK, which bypasses ADC token exchange and sends the string <authenticated> as an x-goog-api-key header to aiplatform.googleapis.com.

Root Cause

Two layers contribute to the bug:

Layer 1: pi-ai env-api-keys.js

When GOOGLE_APPLICATION_CREDENTIALS + GOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_LOCATION are all set, getEnvApiKey("google-vertex") returns the marker string "<authenticated>":

// pi-ai/dist/env-api-keys.js
if (hasCredentials && hasProject && hasLocation) {
    return "<authenticated>";
}

Layer 2: OpenClaw reply-*.jsresolveEnvApiKey()

OpenClaw calls getEnvApiKey() and blindly passes the result as apiKey:

// openclaw/dist/reply-Bm8VrLQh.js line ~36942
if (normalized === "google-vertex") {
    const envKey = getEnvApiKey(normalized);  // returns "<authenticated>"
    if (!envKey) return null;
    return {
        apiKey: envKey,    // "<authenticated>" treated as a real key!
        source: "gcloud adc"
    };
}

Layer 3: pi-ai google-vertex.js

The correctly-implemented google-vertex.js provider checks options.apiKey:

function resolveApiKey(options) {
    return options?.apiKey || process.env.GOOGLE_CLOUD_API_KEY;
}

const client = apiKey
    ? createClientWithApiKey(model, apiKey, ...)   // ← takes this path with "<authenticated>"!
    : createClient(model, project, location, ...); // ← should take this ADC path

Since options.apiKey is "<authenticated>" (truthy), it uses createClientWithApiKey() which passes apiKey: "<authenticated>" to new GoogleGenAI({ vertexai: true, apiKey: "<authenticated>" }).

Layer 4: @google/genai SDK 1.45.0

The SDK constructor sees apiKey is set and clears project/location:

if ((envProject || envLocation) && options.apiKey) {
    console.debug('The user provided Vertex AI API key will take precedence...');
    this.project = undefined;
    this.location = undefined;
}

Then sends <authenticated> as x-goog-api-key header → Google returns 401.

Expected Behavior

When ADC is configured (service account JSON + project + location), OpenClaw should:

  1. NOT pass "<authenticated>" as apiKey to pi-ai stream options
  2. Let google-vertex.js's resolveApiKey() return undefined
  3. Which correctly invokes createClient() with vertexai: true + project + location

Suggested Fix

In resolveEnvApiKey() (OpenClaw side), when the provider is google-vertex and the env key is the <authenticated> marker, return null (or omit apiKey) so the pi-ai google-vertex provider falls through to the ADC path:

if (normalized === "google-vertex") {
    const envKey = getEnvApiKey(normalized);
    if (!envKey) return null;
    // Don't pass the marker as an actual apiKey
    if (envKey === "<authenticated>") {
        return { apiKey: undefined, source: "gcloud adc" };
    }
    return { apiKey: envKey, source: "gcloud adc" };
}

Alternatively, pi-ai's google-vertex.js should filter out the <authenticated> marker in resolveApiKey().

Environment

  • OpenClaw: 2026.3.13 (61d171a)
  • pi-ai: 0.58.0
  • @google/genai: 1.45.0
  • Node.js: v24.14.0
  • OS: macOS (darwin)
  • Auth: Service account JSON via GOOGLE_APPLICATION_CREDENTIALS
  • gcloud ADC: Working (gcloud auth application-default print-access-token succeeds)

Reproduction

  1. Configure Google Vertex AI with service account ADC:
    GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
    GOOGLE_CLOUD_PROJECT=my-project
    GOOGLE_CLOUD_LOCATION=global
    
  2. Set default model to google-vertex/gemini-3-flash-preview
  3. Run openclaw models status --probe
  4. Observe 401: "API keys are not supported by this API. Expected OAuth2 access token"
  5. The warning "The user provided Vertex AI API key will take precedence" confirms the SDK received an API key instead of ADC credentials

Metadata

Metadata

Assignees

Labels

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