{"record":{"id":"95f9bbe01f85ec0f","repo":"Automattic/mongoose","slug":"cannot-set-a-document-s-session-to-a-session-that","errorCode":null,"errorMessage":"Cannot set a document's session to a session that has ended. Make sure you haven't called `endSession()` on the session you are passing to `$session()`.","messagePattern":"Cannot set a document's session to a session that has ended\\. Make sure you haven't called `endSession\\(\\)` on the session you are passing to `\\$session\\(\\)`\\.","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/document.js","lineNumber":985,"sourceCode":" *\n * @param {ClientSession} [session] overwrite the current session\n * @return {ClientSession}\n * @method $session\n * @api public\n * @memberOf Document\n */\n\nDocument.prototype.$session = function $session(session) {\n  if (arguments.length === 0) {\n    if (this.$__.session?.hasEnded) {\n      this.$__.session = null;\n      return null;\n    }\n    return this.$__.session;\n  }\n\n  if (session?.hasEnded) {\n    throw new MongooseError('Cannot set a document\\'s session to a session that has ended. Make sure you haven\\'t ' +\n      'called `endSession()` on the session you are passing to `$session()`.');\n  }\n\n  if (session == null && this.$__.session == null) {\n    return;\n  }\n\n  this.$__.session = session;\n\n  if (!this.$isSubdocument) {\n    const subdocs = this.$getAllSubdocs();\n    for (const child of subdocs) {\n      child.$session(session);\n    }\n  }\n\n  return session;\n};","sourceCodeStart":967,"sourceCodeEnd":1003,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/document.js#L967-L1003","documentation":"$session(session) attaches a ClientSession to the document (and propagates it to subdocuments) so subsequent saves run inside it. Mongoose rejects sessions whose `hasEnded` flag is set: after endSession() the session can carry no further operations, so attaching one would guarantee driver failures on every later command.","triggerScenarios":"`const s = await conn.startSession(); await s.endSession(); doc.$session(s)`; storing a session on a document past the end of a withTransaction()/withSession() block (both end the session when their callback resolves); sessions ended by connection.close().","commonSituations":"Session lifecycle owned by a request wrapper while documents outlive the request; caching or pooling ClientSession objects; ending the session in a finally block before the last save() has run.","solutions":["Call `doc.$session(null)` once the session's work is done, and start a fresh session with conn.startSession() for later operations","Move endSession() to after the last operation that uses the session (end of transaction/request)","Guard every attach: `if (session != null && !session.hasEnded) doc.$session(session)`"],"exampleFix":"// before\nawait session.endSession();\ndoc.$session(session); // throws: session already ended\n\n// after\nawait session.endSession();\ndoc.$session(null);\nconst s2 = await conn.startSession();\ndoc.$session(s2);","handlingStrategy":"validation","validationCode":"function attachSession(doc, session) {\n  if (session != null && session.hasEnded) {\n    throw new Error('Refusing to attach an ended session; start a new one');\n  }\n  doc.$session(session ?? null);\n}","typeGuard":"/** @param {import('mongodb').ClientSession | null | undefined} s */\nconst isUsableSession = (s) => s == null || s.hasEnded !== true;","tryCatchPattern":"try {\n  doc.$session(s);\n} catch (err) {\n  if (/session that has ended/.test(err.message)) {\n    doc.$session(null);\n    s = await conn.startSession();\n    doc.$session(s);\n  } else { throw err; }\n}","preventionTips":["Treat a session as dead as soon as withTransaction()/withSession() callbacks return","Never pool or cache ClientSession objects across requests","End sessions only in the scope that created them, after the final await"],"tags":["mongoose","sessions","transactions","mongodb-driver"],"backgroundTag":"mongodb-session-ended","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}