mongodb/node-mongodb-native · error · MongoExpiredSessionError

Use of expired sessions is not permitted

Error message

Use of expired sessions is not permitted

What it means

When an explicit ClientSession is passed to an operation, executeOperation (src/operations/execute_operation.ts:88) checks session.hasEnded. If the session has already ended (via endSession, commit with no continuation, or CSOT timeout), a MongoExpiredSessionError is thrown. Sessions are single-use resources and cannot be recycled after ending.

Source

Thrown at src/operations/execute_operation.ts:88

    // TODO(NODE-3483): Extend MongoRuntimeError
    throw new MongoRuntimeError('This method requires a valid operation instance');
  }

  const topology =
    client.topology == null
      ? await abortable(autoConnect(client), operation.options)
      : client.topology;

  // The driver sessions spec mandates that we implicitly create sessions for operations
  // that are not explicitly provided with a session.
  let session = operation.session;
  let owner: symbol | undefined;

  if (session == null) {
    owner = Symbol();
    session = client.startSession({ owner, explicit: false });
  } else if (session.hasEnded) {
    throw new MongoExpiredSessionError('Use of expired sessions is not permitted');
  } else if (
    session.snapshotEnabled &&
    maxWireVersion(topology) < MIN_SUPPORTED_SNAPSHOT_READS_WIRE_VERSION
  ) {
    throw new MongoCompatibilityError('Snapshot reads require MongoDB 5.0 or later');
  } else if (session.client !== client) {
    throw new MongoInvalidArgumentError('ClientSession must be from the same MongoClient');
  }

  operation.session ??= session;

  const readPreference = operation.readPreference ?? ReadPreference.primary;
  const inTransaction = !!session?.inTransaction();

  const hasReadAspect = operation.hasAspect(Aspect.READ_OPERATION);

  if (
    inTransaction &&

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Do not reuse a session after endSession(); start a fresh session with client.startSession() for each logical unit of work.
  2. If using withTransaction, let the helper manage the session lifecycle and do not pass the same session to subsequent operations.
  3. If using timeoutMS/CSOT, increase the timeout or restructure the workload so the session does not expire before all operations complete.
  4. Check session.hasEnded before using it if you are unsure of its state.

Example fix

// before
const session = client.startSession();
await session.endSession();
await collection.insertOne({ a: 1 }, { session }); // throws

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

Strategy: validation

Validate before calling

function isSessionUsable(session: ClientSession): boolean {
  return !session.hasEnded;
}
// usage:
if (!isSessionUsable(session)) {
  session = client.startSession();
}

Type guard

const isUsableSession = (s: ClientSession): boolean => !s.hasEnded;

Try / catch

try {
  await collection.insertOne(doc, { session });
} catch (err) {
  if (err instanceof MongoExpiredSessionError) {
    session = client.startSession();
    // retry with new session if appropriate
  } else throw err;
}

Prevention

When it happens

Trigger: Passing a session to an operation after calling session.endSession(), after session.withTransaction has completed, or after a CSOT (Client Server Operation Timeout) has expired the session.

Common situations: Manual session lifecycle management where endSession() is called too early, reusing a session across multiple withTransaction blocks, or a timeoutMS that causes the session to expire mid-workflow.

Related errors


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