Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a session to an existing doc sometimes crashes population #15210

Open
2 tasks done
BobBatard opened this issue Jan 28, 2025 · 1 comment · May be fixed by #15231
Open
2 tasks done

Adding a session to an existing doc sometimes crashes population #15210

BobBatard opened this issue Jan 28, 2025 · 1 comment · May be fixed by #15231
Labels
new feature This change adds new functionality, like a new method or class
Milestone

Comments

@BobBatard
Copy link

BobBatard commented Jan 28, 2025

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

8.9.5

Node.js version

22.13.0

MongoDB server version

8.0.1

Typescript version (if applicable)

No response

Description

When finding a doc without using a session, then adding the session to the doc (with .$session) and then calling populate, a TransientTransactionError sometimes occurs (30% of the time on my machine).

MongoServerError: Given transaction number 5 does not match any in-progress transactions. The active transaction number is 4
    at Connection.sendCommand (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/cmap/connection.js:296:27)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async Connection.command (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/cmap/connection.js:323:26)
    at async Server.command (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/sdam/server.js:170:29)
    at async FindOperation.execute (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/operations/find.js:36:16)
    at async tryOperation (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/operations/execute_operation.js:203:20)
    at async executeOperation (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/operations/execute_operation.js:73:16)
    at async FindCursor._initialize (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/cursor/find_cursor.js:60:26)
    at async FindCursor.cursorInit (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/cursor/abstract_cursor.js:607:27)
    at async FindCursor.fetchBatch (/Users/bob/Documents/work/inmemori/crm_api/mongoose-bson/node_modules/mongodb/lib/cursor/abstract_cursor.js:641:13) {
  errorResponse: {
    errorLabels: [ 'TransientTransactionError' ],
    ok: 0,
    errmsg: 'Given transaction number 5 does not match any in-progress transactions. The active transaction number is 4',
    code: 251,
    codeName: 'NoSuchTransaction',
    '$clusterTime': {
      clusterTime: new Timestamp({ t: 1738078993, i: 14 }),
      signature: [Object]
    },
    operationTime: new Timestamp({ t: 1738078993, i: 14 })
  },
  ok: 0,
  code: 251,
  codeName: 'NoSuchTransaction',
  '$clusterTime': {
    clusterTime: new Timestamp({ t: 1738078993, i: 14 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: 0
    }
  },
  operationTime: new Timestamp({ t: 1738078993, i: 14 }),
  [Symbol(errorLabels)]: Set(1) { 'TransientTransactionError' }
}

Steps to Reproduce

import mongoose from 'mongoose'

const db = await mongoose.createConnection('mongodb://localhost:27017/test').asPromise();

await db.dropDatabase()

const SchemaA = new mongoose.Schema({ name: String })
const SchemaB = new mongoose.Schema({ name: String })
const SchemaC = new mongoose.Schema({ name: String })
const SchemaD = new mongoose.Schema({
	refA: { type: mongoose.Types.ObjectId, ref: 'modelA' },
	refB: { type: mongoose.Types.ObjectId, ref: 'modelB' },
	refC: { type: mongoose.Types.ObjectId, ref: 'modelC' }
})

const modelA = db.model('modelA', SchemaA)
const modelB = db.model('modelB', SchemaB)
const modelC = db.model('modelC', SchemaC)
const modelD = db.model('modelD', SchemaD)

const docA = await modelA.create({ name: 'testA' })
const docB = await modelB.create({ name: 'testB' })
const docC = await modelC.create({ name: 'testC' })

await modelD.create({ refA: docA, refB: docB, refC: docC })

const session = await db.startSession()

await session.withTransaction(async () => {
	try{
		const docD = await modelD
			.findOne()
			// .session(session) // enabling this line fixes the problem

		docD.$session(session)

		// keeping only one path to populate also fixes the problem
		await docD
			.populate([
				{ path: 'refA' },
				{ path: 'refB' },
				{ path: 'refC' }
			])

		console.log(docD)
	}
	catch(e){
		console.log('error', e)
	}
}, session)

process.exit()

Expected Behavior

The script should always log this

{
  _id: new ObjectId('6798fbab874665ce128f8a4e'),
  refA: {
    _id: new ObjectId('6798fbab874665ce128f8a48'),
    name: 'testA',
    __v: 0
  },
  refB: {
    _id: new ObjectId('6798fbab874665ce128f8a4a'),
    name: 'testB',
    __v: 0
  },
  refC: {
    _id: new ObjectId('6798fbab874665ce128f8a4c'),
    name: 'testC',
    __v: 0
  },
  __v: 0
}
@vkarpov15 vkarpov15 added the confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. label Feb 3, 2025
@vkarpov15
Copy link
Collaborator

The error is expected currently because Mongoose populate() always populates paths in parallel, but MongoDB only supports 1 operation per transaction at a time so we would have to populate in series. Similar issues: #15091, #14603, https://jira.mongodb.org/browse/NODE-6190. We're working on a fix, but in the meantime you should do the following:

                // Populate one path at a time
		await docD.populate('refA');
                await docD.populate('refB');
                await docD.populate('refC');

@vkarpov15 vkarpov15 added this to the 8.11 milestone Feb 4, 2025
@vkarpov15 vkarpov15 added new feature This change adds new functionality, like a new method or class and removed confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. labels Feb 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature This change adds new functionality, like a new method or class
Projects
None yet
2 participants