{"record":{"id":"e2ab728239dc2e46","repo":"mongodb/node-mongodb-native","slug":"cursor-returned-a-null-document-but-the-cursor","errorCode":null,"errorMessage":"Cursor returned a `null` document, but the cursor is not exhausted.  Mapping documents to `null` is not supported in the cursor transform.","messagePattern":"Cursor returned a `null` document, but the cursor is not exhausted\\.  Mapping documents to `null` is not supported in the cursor transform\\.","errorType":"exception","errorClass":"MongoAPIError","httpStatus":null,"severity":"error","filePath":"src/cursor/abstract_cursor.ts","lineNumber":1076,"sourceCode":"        // @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.\n        this.emit('close');\n      }\n    } finally {\n      this.hasEmittedClose = true;\n    }\n  }\n\n  /** @internal */\n  private async transformDocument(document: NonNullable<TSchema>): Promise<NonNullable<TSchema>> {\n    if (this.transform == null) return document;\n\n    try {\n      const transformedDocument = this.transform(document);\n      // eslint-disable-next-line no-restricted-syntax\n      if (transformedDocument === null) {\n        const TRANSFORM_TO_NULL_ERROR =\n          'Cursor returned a `null` document, but the cursor is not exhausted.  Mapping documents to `null` is not supported in the cursor transform.';\n        throw new MongoAPIError(TRANSFORM_TO_NULL_ERROR);\n      }\n      return transformedDocument;\n    } catch (transformError) {\n      try {\n        await this.close();\n      } catch (closeError) {\n        squashError(closeError);\n      }\n      throw transformError;\n    }\n  }\n\n  /** @internal */\n  protected throwIfInitialized() {\n    if (this.initialized) throw new MongoCursorInUseError();\n  }\n}\n","sourceCodeStart":1058,"sourceCodeEnd":1094,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/cursor/abstract_cursor.ts#L1058-L1094","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Never return null from a map/transform; wrap nullable values in an object, e.g. doc => ({ value: doc.value ?? null }).","Return undefined instead of null if you want a 'no value' that does not end iteration, though mapping to undefined is fragile too.","Filter out documents you do not want with a $match stage rather than mapping them to null.","Use a Readable stream with its own end semantics if you need null as a legitimate data value."],"exampleFix":"// before: map returns null for some docs\nconst cursor = collection.find({}).map(doc => doc.optionalField ?? null);\n\n// after: wrap the nullable value so the transform never returns null\nconst cursor = collection.find({}).map(doc => ({ value: doc.optionalField ?? null }));","handlingStrategy":"validation","validationCode":"// Reject transforms that can return null before assigning them\nfunction safeMap<T, R>(cursor: FindCursor<T>, fn: (doc: T) => R): FindCursor<NonNullable<R>> {\n  return cursor.map(doc => {\n    const r = fn(doc);\n    if (r === null) throw new TypeError('cursor transform returned null; wrap nullable values in an object');\n    return r as NonNullable<R>;\n  });\n}","typeGuard":null,"tryCatchPattern":"try {\n  await cursor.toArray();\n} catch (err) {\n  if (err instanceof MongoAPIError && /Mapping documents to `null`/.test(err.message)) {\n    // fix the transform to never return null, then re-run\n  } else {\n    throw err;\n  }\n}","preventionTips":["Never return null from map(); wrap nullable values in an object.","Filter unwanted documents with $match instead of mapping them to null.","Prefer returning undefined or a sentinel object over null."],"tags":["cursor","transform","map","data-loss-prevention","logic-error"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}