mem0ai/mem0 · error · Error

Failed to parse googleServiceAccountJson

Error message

Failed to parse googleServiceAccountJson: ${err.message}

What it means

VertexAIEmbedder accepts a Google service account as a JSON string (or parsed object) via config.googleServiceAccountJson. When a string is supplied, it must be parseable JSON; JSON.parse failure is wrapped in this error with the underlying parse message (e.g. 'Unexpected token ... in JSON at position 0').

Solutions

  1. Pass the raw contents of the downloaded service-account JSON file: readFileSync('sa.json', 'utf8')
  2. If the key lives in an env var, use a file-mounted secret or ensure the variable holds the exact JSON text; validate with JSON.parse before constructing the embedder
  3. If credentials are base64-encoded in your pipeline, decode before passing
  4. Prefer vertexCredentialsJson with a file path if your runtime mounts the key as a file

Example fix

// before
new VertexAIEmbedder({ googleServiceAccountJson: "/secrets/sa.json" }); // path, not JSON

// after
new VertexAIEmbedder({
  googleServiceAccountJson: require("fs").readFileSync("/secrets/sa.json", "utf8"),
});
Defensive patterns

Strategy: validation

Validate before calling

if (typeof creds === "string") {
  try { JSON.parse(creds); } catch {
    throw new Error("googleServiceAccountJson is not valid JSON - pass file contents, not a path");
  }
}

Type guard

function isServiceAccountJsonParseError(err: unknown): boolean {
  return err instanceof Error && err.message.startsWith("Failed to parse googleServiceAccountJson");
}

Try / catch

try {
  embedder = new VertexAIEmbedder(cfg);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Failed to parse googleServiceAccountJson")) {
    throw new Error("Service account JSON is malformed - re-export the key file verbatim");
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing the path to a key file instead of its contents; passing the JSON with smart quotes, newlines mangled by shell/env interpolation, or trailing characters; base64-encoded credentials passed without decoding; passing YAML or a PEM key instead of the service-account JSON.

Common situations: Storing the service account in an env var that strips or escapes quotes (Docker/Kubernetes secret handling); copy-paste from a terminal that replaced quotes; confusion between vertexCredentialsJson (file path) and googleServiceAccountJson (contents).

Understand the failure class

Related errors


AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15). Data as JSON: /api/errors/52acb001d068f7da. Report an issue: GitHub.

Appendix: source

Thrown at mem0-ts/src/oss/src/embeddings/vertexai.ts:89

    this.embeddingTypes = {
      add: config.memoryAddEmbeddingType || "RETRIEVAL_DOCUMENT",
      update: config.memoryUpdateEmbeddingType || "RETRIEVAL_DOCUMENT",
      search: config.memorySearchEmbeddingType || "RETRIEVAL_QUERY",
    };

    const endpoint = `${this.location}-aiplatform.googleapis.com`;
    this.clientOptions = { apiEndpoint: endpoint };

    if (config.vertexCredentialsJson) {
      this.clientOptions.keyFilename = config.vertexCredentialsJson;
    } else if (config.googleServiceAccountJson) {
      try {
        this.clientOptions.credentials =
          typeof config.googleServiceAccountJson === "string"
            ? JSON.parse(config.googleServiceAccountJson)
            : config.googleServiceAccountJson;
      } catch (err) {
        throw new Error(
          "Failed to parse googleServiceAccountJson: " + (err as Error).message,
        );
      }
    }
  }

  private async initClient(): Promise<void> {
    // Memoized so concurrent embed() calls share one client instead of each
    // racing to build (and leak) their own gRPC channel.
    if (!this.initPromise) {
      this.initPromise = this.createClient().catch((err) => {
        this.initPromise = undefined;
        throw err;
      });
    }
    await this.initPromise;
  }

View on GitHub (pinned to 001c235229)