continuedev/continue · error · Error

VertexAI: keyJson must contain a valid private key

Error message

VertexAI: keyJson must contain a valid private key

What it means

When authenticating with keyJson, the adapter parses the JSON and requires a private_key field. If parsing succeeds but private_key is absent, this error is thrown; malformed JSON would instead throw from JSON.parse.

Source

Thrown at packages/openai-adapters/src/apis/VertexAI.ts:103

      // Standard mode validation
      if (!region || !projectId) {
        throw new Error(
          "region and projectId are required for VertexAI (when not using express/apiKey mode)",
        );
      }
      if (keyFile && keyJson) {
        throw new Error(
          "VertexAI credentials can be configured with either keyFile or keyJson but not both",
        );
      }
    }

    // Set up authentication client
    if (keyJson) {
      try {
        const parsed = JSON.parse(keyJson);
        if (!parsed?.private_key) {
          throw new Error("VertexAI: keyJson must contain a valid private key");
        }
        parsed.private_key = parsed.private_key.replace(/\\n/g, "\n");
        const jsonClient = auth.fromJSON(parsed);
        if (jsonClient instanceof JWT) {
          jsonClient.scopes = [VertexAIApi.AUTH_SCOPES];
        } else {
          throw new Error("VertexAI: keyJson must be a valid JWT");
        }
        this.clientPromise = Promise.resolve(jsonClient);
      } catch (e) {
        throw new Error("VertexAI: Failed to parse keyJson");
      }
    } else if (keyFile) {
      if (typeof keyFile !== "string") {
        throw new Error("VertexAI: keyFile must be a string");
      }
      this.clientPromise = new GoogleAuth({
        scopes: VertexAIApi.AUTH_SCOPES,

View on GitHub (pinned to 5522c6f44c)

Solutions

  1. Regenerate and download a full service-account JSON key from GCP IAM and use its exact contents
  2. Verify the JSON includes private_key, client_email, and project_id before passing it
  3. Ensure \\n sequences inside private_key are preserved (the adapter normalizes them itself)

Example fix

// before
keyJson: JSON.stringify({ type: 'service_account', project_id: 'p' }) // no private_key
// after
keyJson: fs.readFileSync('svc-account.json', 'utf8') // full service-account key file
Defensive patterns

Strategy: validation

Validate before calling

const parsed = JSON.parse(keyJson); if (!parsed.private_key) throw new Error('keyJson is not a service-account key');

Type guard

const isServiceAccountKey = (s: string): boolean => { try { return 'private_key' in JSON.parse(s); } catch { return false; } };

Try / catch

try { new VertexAIApi(cfg); } catch (e) { if (e.message.includes('valid private key')) throw new ConfigError('keyJson must be a full service-account JSON key'); throw e; }

Prevention

When it happens

Trigger: Passing a keyJson string that is valid JSON but lacks private_key — e.g. a cropped service-account file, a JWT payload, or a Firebase web config.

Common situations: Copying the wrong JSON from Google Cloud console; env var truncation breaking the file; passing a key-file with escaped quotes mangled; using a bare OAuth client config instead of a service-account key.

Related errors


AI-assisted analysis of continuedev/continue@5522c6f44c (2026-08-27). Data as JSON: /api/errors/7f5060f42af214fa. Report an issue: GitHub.