Bug Description
When using the google-vertex provider with Application Default Credentials (ADC) via a service account, OpenClaw passes the literal string "<authenticated>" as options.apiKey to the pi-ai stream handler, which then tries to use it as an actual API key instead of falling through to ADC.
Root Cause
pi-ai's getEnvApiKey("google-vertex") returns "<authenticated>" as a sentinel value when GOOGLE_APPLICATION_CREDENTIALS + GOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_LOCATION are all set.
- OpenClaw's
resolveApiKeyForProvider calls resolveEnvApiKey("google-vertex") → gets { apiKey: "<authenticated>", source: "gcloud adc" }.
- This gets passed as
options.apiKey to pi-ai's streamGoogleVertex handler.
- The handler's
resolveApiKey(options) sees a truthy apiKey → calls createClientWithApiKey("<authenticated>") instead of createClient() (which would use ADC).
- The
@google/genai SDK sends "<authenticated>" as the API key to Vertex AI → 401 CREDENTIALS_MISSING.
Expected Behavior
When ADC credentials are configured for google-vertex, the handler should use new GoogleGenAI({ vertexai: true, project, location }) (the ADC path), not pass a sentinel string as an API key.
Workaround
Two changes are needed:
1. Set auth: "oauth" on the google-vertex provider in openclaw.json:
{
"google-vertex": {
"models": [...],
"baseUrl": "https://aiplatform.googleapis.com",
"auth": "oauth"
}
}
2. Patch pi-ai's resolveApiKey in node_modules/@mariozechner/pi-ai/dist/providers/google-vertex.js:
// Original:
function resolveApiKey(options) {
return options?.apiKey || process.env.GOOGLE_CLOUD_API_KEY;
}
// Patched:
function resolveApiKey(options) {
const _k = options?.apiKey || process.env.GOOGLE_CLOUD_API_KEY;
return (_k && !_k.startsWith("<")) ? _k : undefined;
}
Suggested Fix
Either:
- In OpenClaw: Check if the resolved apiKey is the
"<authenticated>" sentinel before passing it to the stream handler. If so, pass undefined instead, or pass a separate flag like { useAdc: true }.
- In pi-ai: Have
streamGoogleVertex check for the sentinel in resolveApiKey and treat it as "no key" (falling through to ADC).
- Ideally both: The sentinel pattern is fragile. A dedicated auth mode field would be more robust.
Additional Context
auth: "oauth" on the provider config is supposed to skip API key resolution (via resolveProviderAuthOverride), but resolveApiKeyForProvider still calls resolveEnvApiKey() even when authOverride === "oauth". The override only blocks aws-sdk and resolveSyntheticLocalProviderAuth.
- The
api field cannot be set to "google-vertex" (schema enum doesn't include it), but omitting it works because OpenClaw infers the handler from the provider name.
- The
"<authenticated>" sentinel is also used for amazon-bedrock — same issue may exist there.
Environment
- OpenClaw 2026.3.13
- pi-ai (bundled version)
- macOS (arm64)
- Service account auth via
GOOGLE_APPLICATION_CREDENTIALS
Bug Description
When using the
google-vertexprovider with Application Default Credentials (ADC) via a service account, OpenClaw passes the literal string"<authenticated>"asoptions.apiKeyto the pi-ai stream handler, which then tries to use it as an actual API key instead of falling through to ADC.Root Cause
pi-ai'sgetEnvApiKey("google-vertex")returns"<authenticated>"as a sentinel value whenGOOGLE_APPLICATION_CREDENTIALS+GOOGLE_CLOUD_PROJECT+GOOGLE_CLOUD_LOCATIONare all set.resolveApiKeyForProvidercallsresolveEnvApiKey("google-vertex")→ gets{ apiKey: "<authenticated>", source: "gcloud adc" }.options.apiKeyto pi-ai'sstreamGoogleVertexhandler.resolveApiKey(options)sees a truthyapiKey→ callscreateClientWithApiKey("<authenticated>")instead ofcreateClient()(which would use ADC).@google/genaiSDK sends"<authenticated>"as the API key to Vertex AI → 401 CREDENTIALS_MISSING.Expected Behavior
When ADC credentials are configured for
google-vertex, the handler should usenew GoogleGenAI({ vertexai: true, project, location })(the ADC path), not pass a sentinel string as an API key.Workaround
Two changes are needed:
1. Set
auth: "oauth"on the google-vertex provider in openclaw.json:{ "google-vertex": { "models": [...], "baseUrl": "https://aiplatform.googleapis.com", "auth": "oauth" } }2. Patch pi-ai's
resolveApiKeyinnode_modules/@mariozechner/pi-ai/dist/providers/google-vertex.js:Suggested Fix
Either:
"<authenticated>"sentinel before passing it to the stream handler. If so, passundefinedinstead, or pass a separate flag like{ useAdc: true }.streamGoogleVertexcheck for the sentinel inresolveApiKeyand treat it as "no key" (falling through to ADC).Additional Context
auth: "oauth"on the provider config is supposed to skip API key resolution (viaresolveProviderAuthOverride), butresolveApiKeyForProviderstill callsresolveEnvApiKey()even whenauthOverride === "oauth". The override only blocksaws-sdkandresolveSyntheticLocalProviderAuth.apifield cannot be set to"google-vertex"(schema enum doesn't include it), but omitting it works because OpenClaw infers the handler from the provider name."<authenticated>"sentinel is also used foramazon-bedrock— same issue may exist there.Environment
GOOGLE_APPLICATION_CREDENTIALS