mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Could not serialize ns info to BSON

Error message

Could not serialize ns info to BSON

What it means

Companion to the operation serialization error, thrown when BSON cannot serialize the namespace-info document ({ ns: model.namespace }) for a client bulk write batch. Because ns is normally just a string, this error almost always indicates that the namespace string itself is malformed in a way BSON rejects (e.g. contains a NUL byte or invalid UTF-8).

Solutions

  1. Inspect error.cause for the precise serialization failure.
  2. Sanitize the namespace string: ensure it matches /^[^.\\/]*\\.[^.\\/]*$/ and contains only printable characters.
  3. Build namespaces from known database + collection names rather than concatenating raw user input.

Example fix

// before
await client.bulkWrite([{
  insertOne: { namespace: 'db\\0coll', document: { a: 1 } } // contains NUL byte
}]);

// after
await client.bulkWrite([{
  insertOne: { namespace: 'db.coll', document: { a: 1 } }
}]);
Defensive patterns

Strategy: validation

Validate before calling

const NS_RE = /^[^.\/$]*\.[^.\/$]*$/;
if (!NS_RE.test(namespace) || /[\x00-\x1f]/.test(namespace)) {
  throw new Error(`Invalid namespace: ${JSON.stringify(namespace)}`);
}

Type guard

const isValidNamespace = (v: unknown): v is string =>
  typeof v === 'string' && /^[^.\/$]*\.[^.\/$]*$/.test(v) && ![...v].some(c => c.charCodeAt(0) < 32);

Prevention

When it happens

Trigger: Passing a namespace that contains binary/NUL characters or otherwise invalid UTF-8 sequences in any ClientBulkWriteModel.namespace field.

Common situations: Constructing namespace strings dynamically from untrusted input that includes control characters; copying a buffer into a string accidentally; rare driver-internal corruption.

Related errors


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

Appendix: source

Thrown at src/operations/client_bulk_write/command_builder.ts:174

        }
      } else {
        // The namespace is not already in the nsInfo so we will set it in the map, and
        // construct our nsInfo and ops documents and buffers.
        namespaces.set(ns, currentNamespaceIndex);
        const nsInfo = { ns: ns };
        const operation = buildOperation(
          model,
          currentNamespaceIndex,
          this.pkFactory,
          this.options
        );
        let nsInfoBuffer;
        let operationBuffer;
        try {
          nsInfoBuffer = BSON.serialize(nsInfo);
          operationBuffer = BSON.serialize(operation);
        } catch (cause) {
          throw new MongoInvalidArgumentError(`Could not serialize ns info to BSON`, { cause });
        }

        validateBufferSize('nsInfo', nsInfoBuffer, maxBsonObjectSize);
        validateBufferSize('ops', operationBuffer, maxBsonObjectSize);

        // Check if the operation and nsInfo buffers can fit in the command. If they
        // can, then add the operation and nsInfo to their respective document
        // sequences and increment the current length as long as the ops don't exceed
        // the maxWriteBatchSize.
        if (
          commandLength + nsInfoBuffer.length + operationBuffer.length < maxMessageSizeBytes &&
          command.ops.documents.length < maxWriteBatchSize
        ) {
          // Pushing to the ops document sequence returns the total byte length of the document sequence.
          commandLength =
            MESSAGE_OVERHEAD_BYTES +
            command.nsInfo.push(nsInfo, nsInfoBuffer) +
            command.ops.push(operation, operationBuffer);

View on GitHub (pinned to dce7939f86)