mongodb/node-mongodb-native · error · MongoRuntimeError

Unexpected null serverSession for an explicit session

Error message

Unexpected null serverSession for an explicit session

What it means

The `serverSession` getter throws MongoRuntimeError when `_serverSession` is null on an explicit session. Explicit sessions acquire their ServerSession at construction (sessions.ts:192), so a null one implies the session is in an invalid lifecycle state — typically used after its server session was released or never properly acquired.

Solutions

  1. Treat `endSession()` as terminal: never reuse the session afterward.
  2. Use `try/finally` to scope a session: `const s = client.startSession(); try { ... } finally { await s.endSession(); }`.
  3. If pooling sessions in a wrapper, mark them ended and reject further use rather than handing them out again.

Example fix

// before
const session = client.startSession();
await session.endSession();
await collection.findOne({}, { session }); // throws

// after
const session = client.startSession();
try {
  await collection.findOne({}, { session });
} finally {
  await session.endSession();
}
Defensive patterns

Strategy: try-catch

Validate before calling

function assertUsable(session) {
  if (session.hasEnded) throw new Error('session has ended; obtain a new one');
}

Type guard

function isActive(session) {
  return !session.hasEnded;
}

Try / catch

try {
  await collection.findOne({}, { session });
} catch (err) {
  if (err.name === 'MongoRuntimeError' && /explicit session/i.test(err.message)) {
    // session was ended; restart with a fresh one
    session = client.startSession();
  }
}

Prevention

When it happens

Trigger: Accessing `session.serverSession` (directly or via an operation) after `endSession()` has released it; a half-constructed session from a failed `startSession`; an internal race that released the server session prematurely.

Common situations: Reusing a session after `await session.endSession()`; sharing a session across concurrent code paths where one calls endSession; storing sessions in long-lived singletons that get cleaned up elsewhere.

Related errors


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

Appendix: source

Thrown at src/sessions.ts:218

    this.clusterTime = options.initialClusterTime;

    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');

View on GitHub (pinned to dce7939f86)