Skip to content

@google/genai pinned to ^1.45.0 causes a duplicate 16 MB install alongside genai v2 #675

Description

@ScottMansfield

Summary

@google-cloud/agentplatform (and its predecessor @google-cloud/vertexai) pins
@google/genai: ^1.45.0. Any application that also depends on @google/genai@^2.x
— which is the current major — gets two full copies of @google/genai installed,
because the ranges cannot dedupe.

@google/genai is ~16 MB installed, so this is ~16 MB of pure duplication, plus a second
copy of the google-auth-library stack underneath it.

Reproduction

{
  "dependencies": {
    "@google/genai": "^2.9.0",
    "@google-cloud/vertexai": "^1.12.0"
  }
}
$ npm install && du -sh node_modules
54M

$ find node_modules -type d -path '*@google/genai'
node_modules/@google/genai                                      # 2.18.0
node_modules/@google-cloud/vertexai/node_modules/@google/genai  # 1.52.0

The @google/genai pin was introduced in @google-cloud/vertexai@1.11.0 and carried into
@google-cloud/agentplatform.

Secondary effect: broken instanceof

Because the two copies are distinct module instances, classes exported from them are
distinct objects. Downstream code that catches errors originating in the nested copy cannot
use instanceof and has to match structurally instead. A real example from
google/adk-js:

// gRPC transports report NOT_FOUND as a numeric `code`; the `@google/genai` `ApiClient`
// behind the Sessions client throws an `ApiError` carrying a numeric `status` instead.
// Matched structurally, not with `instanceof`: `@google-cloud/vertexai` resolves its own
// copy of `@google/genai`, so its `ApiError` is a different class object.

This is the usual duplicate-instance failure mode and it will keep surfacing as long as two
copies can coexist.

Requested change

Either of:

  1. Widen the range to ^1.45.0 || ^2.0.0 if the v2 surface used here is compatible, or
  2. Make @google/genai a peer dependency (optionally with peerDependenciesMeta), so
    the host application controls the version and there is structurally only ever one copy.

(2) is the more robust option for a library that re-exports and re-throws types from
@google/genai, since it makes the single-instance requirement explicit rather than
incidental.

Compatibility signal

Forcing the nested copy to 2.18.0 via an npm overrides entry, the entry points a
downstream consumer typically touches all still load and construct:

OK   @google-cloud/vertexai
OK   @google-cloud/vertexai/build/src/genai/client.js
OK   @google-cloud/vertexai/build/src/genai/sessions.js
OK   @google-cloud/vertexai/build/src/genai/memories.js
OK   @google-cloud/vertexai/build/src/genai/types.js
OK   new Client({project, location, vertexai: true})

Install tree goes 54 MB → 39 MB. That is obviously not a full compatibility audit — v1→v2
had breaking changes — but it suggests the surface this package depends on may already be
v2-clean, or close to it.

Why downstream can't fix this properly

npm overrides are only honoured in the root project's package.json; an override
declared inside a dependency is ignored (verified). So a library that depends on both
packages cannot dedupe on behalf of its own consumers — only the end application can, and
only by adding an override it shouldn't need to know about.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api: aiplatformIssues related to the googleapis/nodejs-agentplatform API.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions