mongodb/node-mongodb-native · error · MongoBatchReExecutionError

This batch has already been executed, create new batch to ex

Error message

This batch has already been executed, create new batch to execute

What it means

Thrown as MongoBatchReExecutionError when BulkOperationBase.execute() is called on a bulk operation that has already been executed (this.s.executed is true). A BulkOperationBase instance is single-use; once execute() runs, the internal batches are consumed and the instance cannot be reused.

Source

Thrown at src/bulk/common.ts:1183

  get writeConcern(): WriteConcern | undefined {
    return this.s.writeConcern;
  }

  get batches(): Batch[] {
    const batches = [...this.s.batches];
    if (this.isOrdered) {
      if (this.s.currentBatch) batches.push(this.s.currentBatch);
    } else {
      if (this.s.currentInsertBatch) batches.push(this.s.currentInsertBatch);
      if (this.s.currentUpdateBatch) batches.push(this.s.currentUpdateBatch);
      if (this.s.currentRemoveBatch) batches.push(this.s.currentRemoveBatch);
    }
    return batches;
  }

  async execute(options: BulkWriteOptions = {}): Promise<BulkWriteResult> {
    if (this.s.executed) {
      throw new MongoBatchReExecutionError();
    }

    const writeConcern = WriteConcern.fromOptions(options);
    if (writeConcern) {
      this.s.writeConcern = writeConcern;
    }

    // If we have current batch
    if (this.isOrdered) {
      if (this.s.currentBatch) this.s.batches.push(this.s.currentBatch);
    } else {
      if (this.s.currentInsertBatch) this.s.batches.push(this.s.currentInsertBatch);
      if (this.s.currentUpdateBatch) this.s.batches.push(this.s.currentUpdateBatch);
      if (this.s.currentRemoveBatch) this.s.batches.push(this.s.currentRemoveBatch);
    }
    // If we have no operations in the bulk raise an error
    if (this.s.batches.length === 0) {
      throw new MongoInvalidArgumentError('Invalid BulkOperation, Batch cannot be empty');

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Create a fresh bulk op via collection.initializeOrderedBulkOp() / initializeUnorderedBulkOp() before each execute().
  2. In retry logic, rebuild the operation list inside the retry block, not outside it.
  3. Use collection.bulkWrite(ops) for one-shot calls; the driver creates a new internal op each time.

Example fix

// before
const bulk = coll.initializeOrderedBulkOp();
bulk.find({_id:1}).updateOne({$set:{a:1}});
await bulk.execute();
await bulk.execute(); // throws

// after
async function run() {
  const bulk = coll.initializeOrderedBulkOp();
  bulk.find({_id:1}).updateOne({$set:{a:1}});
  return bulk.execute();
}
Defensive patterns

Strategy: validation

Validate before calling

function assertNotExecuted(bulk) {
  if (bulk.s.executed) {
    throw new Error('bulk op already executed; create a new one');
  }
}

Type guard

function isFreshBulkOp(bulk) {
  return bulk != null && bulk.s != null && bulk.s.executed === false;
}

Try / catch

try {
  await bulk.execute();
} catch (e) {
  if (e instanceof MongoBatchReExecutionError) {
    // create a fresh bulk op and rebuild operations
  }
}

Prevention

When it happens

Trigger: Calling await bulk.execute() twice on the same bulk op object. Holding a bulk op in a long-lived variable and calling execute() in a retry loop without creating a fresh instance.

Common situations: Retry logic that re-invokes execute() on failure; reusing a bulk op across request handlers; caching a bulk op instance.

Related errors


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