mongodb/node-mongodb-native · error · MongoRuntimeError

Unexpected null serverSession for an ended implicit session

Error message

Unexpected null serverSession for an ended implicit session

What it means

Thrown by the `serverSession` getter when an implicit (non-explicit) session that has already ended is accessed again (sessions.ts:220). Implicit sessions are created internally per-operation and ended automatically; accessing the server session after `end()` has run means the session is no longer usable.

Source

Thrown at src/sessions.ts:221

    this.operationTime = undefined;
    this.owner = options.owner;
    this.defaultTransactionOptions = { ...options.defaultTransactionOptions };
    this.transaction = new Transaction();
  }

  /** The server id associated with this session */
  get id(): ServerSessionId | undefined {
    return this.serverSession?.id;
  }

  get serverSession(): ServerSession {
    let serverSession = this._serverSession;
    if (serverSession == null) {
      if (this.explicit) {
        throw new MongoRuntimeError('Unexpected null serverSession for an explicit session');
      }
      if (this.hasEnded) {
        throw new MongoRuntimeError('Unexpected null serverSession for an ended implicit session');
      }
      serverSession = this.sessionPool.acquire();
      this._serverSession = serverSession;
    }
    return serverSession;
  }

  get loadBalanced(): boolean {
    return this.client.topology?.description.type === TopologyType.LoadBalanced;
  }

  /** @internal */
  pin(conn: Connection): void {
    if (this.pinnedConnection) {
      throw TypeError('Cannot pin multiple connections to the same session');
    }

    this.pinnedConnection = conn;

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Do not retain or reuse implicit sessions; let the driver manage their lifecycle.
  2. If you need a long-lived session, create an explicit one with `client.startSession()` and end it yourself when done.
  3. Ensure cursors are fully consumed or closed before their session ends.

Example fix

// before
const cursor = coll.find({}, { session: implicitSession });
implicitSession.endSession();
await cursor.next(); // throws
// after
await cursor.next();
implicitSession.endSession();
Defensive patterns

Strategy: validation

Validate before calling

function useImplicitSession(session, fn) {
  if (session.hasEnded) throw new Error('session has ended; obtain a new one');
  return fn();
}

Type guard

function isSessionUsable(session) {
  return session != null && !session.hasEnded;
}

Prevention

When it happens

Trigger: Using an implicit session (e.g. one attached to a cursor) after it was ended; re-running an operation on a cursor whose session was cleaned up; holding a reference to an implicit session past its lifecycle.

Common situations: Iterating a cursor after its owning implicit session was ended; sharing an implicit session handle across async boundaries that outlive the operation; manual `endSession()` on an implicit session followed by further use.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/9605308f4cf45512.json. Report an issue: GitHub.