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
- Treat `endSession()` as terminal: never reuse the session afterward.
- Use `try/finally` to scope a session: `const s = client.startSession(); try { ... } finally { await s.endSession(); }`.
- 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
- Scope every explicit session in try/finally and end it once.
- Never reuse a session across async boundaries after endSession.
- Track session lifecycle in a wrapper that prevents post-end use.
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
- Cannot call abortTransaction after calling commitTransaction
- Cannot call abortTransaction twice
- Cannot call commitTransaction after calling abortTransaction
- ClientSession requires a MongoClient
- ClientSession requires a ServerSessionPool
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)