{"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/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/cursor/abstract_cursor.ts#L1058-L1094","documentation":"Thrown by AbstractCursor.transformDocument() when the user-supplied transform function (set via cursor.map()) returns null for a document. The driver cannot distinguish a null-transformed result from the sentinel null it uses to signal cursor exhaustion in its iteration protocol, so it refuses the mapping entirely. This is a user-API contract error, not a server problem.","triggerScenarios":"Calling cursor.map(doc => conditional ? null : doc), or a transform that legitimately returns null (e.g. filtering via map, or optional fields mapped to null). Triggered on the first document for which the transform yields null during next()/toArray()/forEach()/streaming.","commonSituations":"Using map() to drop documents, projecting a field that can be null, or migrating a filter/map chain from another library that permits null.","solutions":["Do not return null from map(); return a placeholder object (e.g. { __skip: true }) and filter afterwards, or return undefined and filter it out","Use cursor.filter() / a $match stage to drop documents server-side instead of map()","Apply the transform yourself after toArray() rather than via cursor.map()"],"exampleFix":"// before\ncursor.map(doc => doc.active ? doc : null); // throws\n// after (filter server-side)\nconst docs = await coll.find({ active: true }).toArray();\n// or map to a sentinel and post-filter\ncursor.map(doc => doc.active ? doc : undefined);\nconst docs = (await cursor.toArray()).filter(Boolean);","handlingStrategy":"validation","validationCode":"function makeTransform(fn) {\n  return (doc) => {\n    const out = fn(doc);\n    if (out === null) {\n      throw new Error('transform returned null; use filter() instead of map() for dropping docs');\n    }\n    return out;\n  };\n}\n// usage: cursor.map(makeTransform(d => d.active ? d : null)) // fails fast, clearly","typeGuard":"const returnsNonNull = (fn) => (doc) => {\n  const r = fn(doc);\n  if (r == null) throw new Error('transform must not return null/undefined');\n  return r;\n};","tryCatchPattern":"try {\n  await cursor.toArray();\n} catch (e) {\n  if (e instanceof MongoAPIError && /Mapping documents to `null`/.test(e.message)) {\n    // rewrite to filter server-side\n    docs = await coll.find(filter).toArray();\n  } else throw e;\n}","preventionTips":["Never return null from a cursor.map() transform; filter server-side instead","Return undefined and post-filter if you must drop in the transform","Apply transforms after toArray() when null is a legitimate value"],"tags":["cursor","map","transform","user-error"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}