mongodb/node-mongodb-native · error · MongoAPIError

Cursor returned a `null` document, but the cursor is not…

Error message

Cursor returned a `null` document, but the cursor is not exhausted.  Mapping documents to `null` is not supported in the cursor transform.

What it means

Thrown as a MongoAPIError from transformDocument() when the configured transform/map function returns exactly null for a document while the cursor is not exhausted. The cursor uses null internally to signal end-of-stream (next() returns null and for-await stops), so a user transform that maps real documents to null would silently truncate iteration. To prevent data loss the driver detects a null transform result for a non-terminal document and throws, then closes the cursor. Falsy but non-null values (0, '', false) are allowed.

Solutions

  1. Never return null from a map/transform; wrap nullable values in an object, e.g. doc => ({ value: doc.value ?? null }).
  2. Return undefined instead of null if you want a 'no value' that does not end iteration, though mapping to undefined is fragile too.
  3. Filter out documents you do not want with a $match stage rather than mapping them to null.
  4. Use a Readable stream with its own end semantics if you need null as a legitimate data value.

Example fix

// before: map returns null for some docs
const cursor = collection.find({}).map(doc => doc.optionalField ?? null);

// after: wrap the nullable value so the transform never returns null
const cursor = collection.find({}).map(doc => ({ value: doc.optionalField ?? null }));
Defensive patterns

Strategy: validation

Validate before calling

// Reject transforms that can return null before assigning them
function safeMap<T, R>(cursor: FindCursor<T>, fn: (doc: T) => R): FindCursor<NonNullable<R>> {
  return cursor.map(doc => {
    const r = fn(doc);
    if (r === null) throw new TypeError('cursor transform returned null; wrap nullable values in an object');
    return r as NonNullable<R>;
  });
}

Try / catch

try {
  await cursor.toArray();
} catch (err) {
  if (err instanceof MongoAPIError && /Mapping documents to `null`/.test(err.message)) {
    // fix the transform to never return null, then re-run
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: cursor.map(doc => doc ? doc.value : null); cursor.map(() => null); a transform that returns null for a missing optional field; a projection-style map that produces null for some rows.

Common situations: Using map() to extract a nullable field without wrapping in an object; mapping to a value that happens to be null for the first document; refactoring a transform that previously returned undefined (allowed) into one that returns null (not allowed).

Related errors


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

Appendix: source

Thrown at src/cursor/abstract_cursor.ts:1076

        // @ts-expect-error: CursorEvents is generic so Parameters<CursorEvents["close"]> may not be assignable to `[]`. Not sure how to require extenders do not add parameters.
        this.emit('close');
      }
    } finally {
      this.hasEmittedClose = true;
    }
  }

  /** @internal */
  private async transformDocument(document: NonNullable<TSchema>): Promise<NonNullable<TSchema>> {
    if (this.transform == null) return document;

    try {
      const transformedDocument = this.transform(document);
      // eslint-disable-next-line no-restricted-syntax
      if (transformedDocument === null) {
        const TRANSFORM_TO_NULL_ERROR =
          'Cursor returned a `null` document, but the cursor is not exhausted.  Mapping documents to `null` is not supported in the cursor transform.';
        throw new MongoAPIError(TRANSFORM_TO_NULL_ERROR);
      }
      return transformedDocument;
    } catch (transformError) {
      try {
        await this.close();
      } catch (closeError) {
        squashError(closeError);
      }
      throw transformError;
    }
  }

  /** @internal */
  protected throwIfInitialized() {
    if (this.initialized) throw new MongoCursorInUseError();
  }
}

View on GitHub (pinned to dce7939f86)