mongodb/node-mongodb-native · error · MongoInvalidArgumentError

input cluster time must have a valid "signature" property…

Error message

input cluster time must have a valid "signature" property with BSON Binary hash and BSON Long keyId

What it means

`advanceClusterTime` validates the `signature` field: it must exist, `signature.hash` must be a BSON Binary, and `signature.keyId` must be a bigint, number, or BSON Long. Any deviation throws MongoInvalidArgumentError. The check exists because the server signs cluster times and an invalid signature would corrupt auth/cluster-time gossip.

Solutions

  1. Forward the server's `$clusterTime` document intact, including its `signature`.
  2. Use BSON encode/decode for cross-process transport so Binary and Long survive.
  3. When reconstructing, build `Long`/`Binary` instances: `new Long(keyIdLow, keyIdHigh)` and `new Binary(buffer, subtype)`.

Example fix

// before (after JSON round-trip — signature lost BSON types)
session.advanceClusterTime(jsonParsedClusterTime);

// after
import { deserialize } from 'mongodb';
const ct = deserialize(serialisedBuffer);
session.advanceClusterTime(ct.$clusterTime);
Defensive patterns

Strategy: type-guard

Validate before calling

function hasValidSignature(ct) {
  const sig = ct?.signature;
  return sig?.hash?._bsontype === 'Binary' &&
    (typeof sig?.keyId === 'bigint' || typeof sig?.keyId === 'number' || sig?.keyId?._bsontype === 'Long');
}
if (hasValidSignature(ct)) session.advanceClusterTime(ct);

Type guard

function isValidSignedClusterTime(v) {
  if (!v || typeof v !== 'object') return false;
  if (v.clusterTime?._bsontype !== 'Timestamp') return false;
  const sig = v.signature;
  return sig?.hash?._bsontype === 'Binary' &&
    (typeof sig?.keyId === 'bigint' || typeof sig?.keyId === 'number' || sig?.keyId?._bsontype === 'Long');
}

Prevention

When it happens

Trigger: Forwarding a cluster time with a missing or wrong-typed signature; reconstructing the doc after JSON round-trip (Long becomes object, Binary becomes base64 string); stripping signature intentionally for test purposes.

Common situations: Cross-process cluster-time propagation that did not preserve BSON types; test doubles that build cluster time without real signature data; bug in a serialisation layer.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11). Data as JSON: /api/errors/b20c3488273c3d99. Report an issue: GitHub.

Appendix: source

Thrown at src/sessions.ts:336

   * @param clusterTime - the $clusterTime returned by the server from another session in the form of a document containing the `BSON.Timestamp` clusterTime and signature
   */
  advanceClusterTime(clusterTime: ClusterTime): void {
    if (!clusterTime || typeof clusterTime !== 'object') {
      throw new MongoInvalidArgumentError('input cluster time must be an object');
    }
    if (!clusterTime.clusterTime || clusterTime.clusterTime._bsontype !== 'Timestamp') {
      throw new MongoInvalidArgumentError(
        'input cluster time "clusterTime" property must be a valid BSON Timestamp'
      );
    }
    if (
      !clusterTime.signature ||
      clusterTime.signature.hash?._bsontype !== 'Binary' ||
      (typeof clusterTime.signature.keyId !== 'bigint' &&
        typeof clusterTime.signature.keyId !== 'number' &&
        clusterTime.signature.keyId?._bsontype !== 'Long') // apparently we decode the key to number?
    ) {
      throw new MongoInvalidArgumentError(
        'input cluster time must have a valid "signature" property with BSON Binary hash and BSON Long keyId'
      );
    }

    _advanceClusterTime(this, clusterTime);
  }

  /**
   * Used to determine if this session equals another
   *
   * @param session - The session to compare to
   */
  equals(session: ClientSession): boolean {
    if (!(session instanceof ClientSession)) {
      return false;
    }

    if (this.id == null || session.id == null) {

View on GitHub (pinned to dce7939f86)