From cf656c169c182f54b935abf31c3461bb1e753900 Mon Sep 17 00:00:00 2001 From: jeremiahgaylord-web Date: Wed, 25 Feb 2026 17:31:16 -0600 Subject: [PATCH] fix(ai): don't cache false for Vertex ADC credentials during async import race (#1550) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `hasVertexAdcCredentials()` uses dynamic imports to load `node:fs`, `node:os`, and `node:path` to avoid breaking browser/Vite builds. These imports are fired eagerly but resolve asynchronously. If the function is called during gateway startup before those promises resolve, `_existsSync`, `_homedir`, and `_join` are still null — causing the function to cache `false` permanently and never re-evaluate. This means users with valid `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_CLOUD_PROJECT`, and `GOOGLE_CLOUD_LOCATION` configured are silently treated as unauthenticated for Vertex AI. Calls fall back to the AI Studio endpoint (generativelanguage.googleapis.com) which has much stricter rate limits, causing unexpected 429 errors even though Vertex credentials are correctly configured. Fix: in Node.js/Bun environments, return false without caching when the async modules aren't loaded yet, so the next call retries. Only cache false permanently in browser environments where `fs` is genuinely unavailable. Co-authored-by: Jeremiah Gaylord Co-authored-by: Claude Sonnet 4.6 --- packages/ai/src/env-api-keys.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/ai/src/env-api-keys.ts b/packages/ai/src/env-api-keys.ts index fe759320..bff9f360 100644 --- a/packages/ai/src/env-api-keys.ts +++ b/packages/ai/src/env-api-keys.ts @@ -22,9 +22,15 @@ let cachedVertexAdcCredentialsExists: boolean | null = null; function hasVertexAdcCredentials(): boolean { if (cachedVertexAdcCredentialsExists === null) { - // In browser or if node modules not loaded yet, return false + // If node modules haven't loaded yet (async import race at startup), + // return false WITHOUT caching so the next call retries once they're ready. + // Only cache false permanently in a browser environment where fs is never available. if (!_existsSync || !_homedir || !_join) { - cachedVertexAdcCredentialsExists = false; + const isNode = typeof process !== "undefined" && (process.versions?.node || process.versions?.bun); + if (!isNode) { + // Definitively in a browser — safe to cache false permanently + cachedVertexAdcCredentialsExists = false; + } return false; }