Given transaction number does not match any in-progress transactions

given transaction number does not match any in-progress transactions

I am getting above error when trying to create transactions for multiple orders and I am using async/await to create multiple transactions for each order one by one.

Kindly help me to solve this error.

Hi @Naif_Almuqbel, welcome!

In order to help others answer your question, could you answer the following to provide more information:

  • Which MongoDB driver and version are you using ?
  • Which MongoDB server version are you using ?
  • Could you provide the relevant code containing how you create the transaction ?
  • Are you catching TransientTransactionError exception on the code ?
  • Are you running any database commands such as creating a collection, creating an index, dropping a collection, or other types of DDL operations in your transactions ?

Regards,
Wan.

Hi @wan,

I have provided my configuration below:

MongoDB server version is 4.2.3 and it is hosted on atlas.
Driver - NodeJS and version v12.13.1

No TransientTransactionError is occuring and actual error is Given transaction number 2 does not match any in-progress transactions. The active transaction number is 1

Also I am not performing any operations like creating collection, an index, dropping collection and other types of DDL operations

I have provided my code below.
I am running a job to update order status as completed, creating and updating documents in transaction.

function checkOrder() {
    const timeStampNow = new Date().getTime();
    const query = {
             status: {
                     $in: [ Constants.PAID_PAYMENT,
                            Constants.RESCHEDULE_REQUEST_ACCEPTED ]
             },
             expiryDate: {
                   $lte: new Date(timeStampNow)
             },
            isActive: true
       };

  await Request.find(query, async (err, docs) => {
    if (err || Utility.isEmptyObject(docs)) {
        // console.log('error ' + err);
    }
    else {
        try {
            for (let i in docs) {
                let requestData = docs[i];

                const data = {
                    referenceId: requestData.referenceId,
                    status: Constants.COMPLETED
                };

                await updateRequestCronJob(data);
            }
        }
        catch (e) {
            console.log('CRON: error -job', e);
        }
    }
  });
}

async function updateRequestCronJob(data) {

       const status = data.status; // to be updated
       const referenceId = data.referenceId;

       const query = { referenceId: referenceId, isActive: true };

      await Request
               .findOne(query)
               .then(async (request) => {
                       let session = await mongoose.startSession();
                       session.startTransaction();
                   try {
                          const opts = { session };
                          const currentTime = Utility.currentTimeNow();

                          let transactionId = Utility.generateUniqueRandomNumber();

                          let transactionBody = {
                                    transactionId: transactionId,
                                     requestId: referenceId
                             };

            let transactionsAr = [];
            let artistIncome;

            // deduct money from admin & credit to artist

            let orderAmount = request.paymentAmount;
            const artistId = request._artistId._id;

            let commissionAmount = Utility.getCompletionCommission(orderAmount,
                request.commissionPercent);

            artistIncome = orderAmount - commissionAmount;

            transactionBody['amount'] = artistIncome;
            transactionBody['status'] = Constants.TRANSACTION_STATUS_CREDITED;
            transactionBody['from'] = Constants.ADMIN_MONGO_ID;
            transactionBody['fromDesc'] = Constants.TRANSACTION_FROM_SERVICE_INCOME;
            transactionBody['to'] = artistId;
            transactionBody['desc'] = Constants.ARTIST_SERVICE_INCOME;
            transactionBody['type'] = Constants.TRANSACTION_TYPE_DEBIT;
            transactionBody['mode'] = Constants.TRANSACTION_MODE_WALLET;
            transactionBody['createdAt'] = Utility.currentTimeNow();

            transactionsAr.push(transactionBody);

            // save completion commission 
            transactionBody = {};

            transactionBody['transactionId'] = Utility.generateUniqueRandomNumber();
            transactionBody['requestId'] = referenceId;

            transactionBody['amount'] = commissionAmount;
            transactionBody['status'] = Constants.TRANSACTION_STATUS_JAMELAH_COMPLETION_COMMISSION;
            transactionBody['from'] = Constants.ADMIN_MONGO_ID;
            transactionBody['to'] = Constants.ADMIN_MONGO_ID;
            transactionBody['desc'] = Constants.COMPLETION_COMMISSION;
            transactionBody['type'] = Constants.TRANSACTION_TYPE_CREDIT;
            transactionBody['mode'] = Constants.TRANSACTION_MODE_WALLET;
            transactionBody['createdAt'] = Utility.currentTimeNow();

            transactionsAr.push(transactionBody);

            await Transaction.create(transactionsAr, opts)
                .then(res => {
                    //console.log(res);
                    if (Utility.isEmptyObject(res)) {
                        throw new Error('Error in creating transaction.');
                    }
                });

            // b) deposit service amount in artist wallet
            await User.findOneAndUpdate({ _id: artistId },
                {
                    $inc: { 'wallet.balance': artistIncome }
                },
                { session, new: true }).
                then(res => {
                    //console.log(res);
                    if (Utility.isEmptyObject(res)) {
                        throw new Error('Error in crediting artist wallet.');
                    }
                    return res;
                });

            let orderBody = {
                status: status,
                updatedAt: currentTime,
                reviewNotificationTime: Utility.addHoursToCurrentTime(process.env.NOTIFICATION_HOURS_AFTER_COMPLETION ||
                    Config.NOTIFICATION_HOURS_AFTER_COMPLETION),
                artistIncome: artistIncome
            };

            await Request.findOneAndUpdate(
                {
                    referenceId: referenceId
                },
                {
                    $set: orderBody,
                    $push: {
                        statusStages: {
                            status: status,
                            time: currentTime
                        }
                    }
                },
                opts)
                .then(res => {
                    if (Utility.isEmptyObject(res)) {
                        throw new Error('Error in updating order.');
                    }
                    return res;
                });

            await session.commitTransaction();
            session.endSession();
            return true;
        }
        catch (error) {
            await session.abortTransaction();
            session.endSession();
            throw error; 
        }
    })
    .catch(e => {
        return;
    });
}

Thanks for providing more information and code snippets.

It is likely that you’re not seeing the full error message because at the end of function updateRequestCronJob the catch does not throw error. The full error message should look something similar as below:

{ MongoError: Given transaction number 3 does not match any in-progress transactions. The active transaction number is 2
    at Connection.<anonymous> (/vbox/mongo/nodejs/node_modules/mongoose/node_modules/mongodb/lib/core/connection/pool.js:450:61)
    at Connection.emit (events.js:182:13)
    at processMessage (/vbox/mongo/nodejs/node_modules/mongoose/node_modules/mongodb/lib/core/connection/connection.js:384:10)
    at Socket.<anonymous> (/vbox/mongo/nodejs/node_modules/mongoose/node_modules/mongodb/lib/core/connection/connection.js:586:15)
    at Socket.emit (events.js:182:13)
    at addChunk (_stream_readable.js:283:12)
    at readableAddChunk (_stream_readable.js:264:11)
    at Socket.Readable.push (_stream_readable.js:219:10)
    at TCP.onread (net.js:639:20)
  errorLabels: [ 'TransientTransactionError' ],
  operationTime:
   Timestamp { _bsontype: 'Timestamp', low_: 8, high_: 1582506018 },
  ok: 0,
  errmsg:
   'Given transaction number 3 does not match any in-progress transactions. The active transaction number is 2',
  code: 251,
  codeName: 'NoSuchTransaction',
  '$clusterTime':
   { clusterTime:
      Timestamp { _bsontype: 'Timestamp', low_: 14, high_: 1582506018 },
     signature: { hash: [Binary], keyId: 0 } },
  name: 'MongoError',
  [Symbol(mongoErrorContextSymbol)]: {} }

This is likely related to mongoose issue #7502, and SERVER-36428.

You can try to incorporate logic to retry the transaction for transient errors, and also retry the commit for unknown commit error. For example:

async function runTransactionWithRetry(txnFunc, data) {
  let session = await mongoose.startSession(); 
  session.startTransaction(); 
  try {
    await txnFunc(data, session);
  } catch (error) {
    console.log('Transaction aborted. Caught exception during transaction.');

    // If transient error, retry the whole transaction
    if (error.errorLabels && error.errorLabels.indexOf('TransientTransactionError') >= 0) {
      console.log('TransientTransactionError, retrying transaction ...');
      await runTransactionWithRetry(txnFunc, data);
    } else {
        session.abortTransaction();
        console.log("runTransactionWithRetry error: ");
        throw error;
    }
  }
}

async function commitWithRetry(session) {
  try {
    await session.commitTransaction();
    console.log('Transaction committed.');
  } catch (error) {
    if (
      error.errorLabels &&
      error.errorLabels.indexOf('UnknownTransactionCommitResult') >= 0
    ) {
      console.log('UnknownTransactionCommitResult, retrying commit operation ...');
      await commitWithRetry(session);
    } else {
      console.log('Error during commit ...');
      throw error;
    }
  }
}

See more information and snippets on Transactions In Applications: Core API (Switch the code tab to Node.JS)

Regards,
Wan.