Error
Error Code: 21

MongoDB Error 21: Empty Array Operation Attempted

📦 MongoDB
📋

Description

This error indicates that an attempted array update operation, such as `$push` or `$pull`, targeted a field that was either not an array, did not exist, or was an empty array when the operation expected a non-empty one. It prevents modifications that would result in an invalid state or type mismatch.
💬

Error Message

Empty Array Operation
🔍

Known Causes

3 known causes
⚠️
Targeting Non-Array Field
An array update operator was applied to a document field that does not exist or is not an array type.
⚠️
Operation on Empty Array
An array modifier was used on a field that is an empty array, and the operation requires a non-empty array or a specific initial state.
⚠️
Invalid Element for Array
An attempt was made to add an empty array as an element into another array where the schema or operation logic forbids it.
🛠️

Solutions

4 solutions available

1. Validate Query Before Execution easy

Ensure arrays in your query conditions are not empty before attempting operations.

1
Before executing any MongoDB operation that involves an array as a filter or part of an update (e.g., `$in`, `$all`, `$push` to a non-existent array), check if the array variable or expression is empty. If it is, either skip the operation or provide a default non-empty value.
const queryArray = getArrayFromSomeSource();

if (queryArray && queryArray.length > 0) {
  db.collection.find({ field: { $in: queryArray } });
} else {
  // Handle the case where the array is empty, e.g., log a warning or skip the query.
  console.warn('Query array is empty, skipping operation.');
}

2. Conditional Updates for Array Fields medium

Use conditional logic in your application to avoid updating arrays that don't exist or are not intended to be modified.

1
When performing updates, especially with operators like `$push` or `$addToSet`, ensure the target array field exists and is indeed an array. If the field might be missing or null, add checks in your application logic.
const docId = 'some_document_id';
const itemToAdd = 'new_item';

// Fetch the document to check the array's existence and type
db.collection.findOne({ _id: docId }, (err, doc) => {
  if (err) { /* handle error */ }
  if (doc && Array.isArray(doc.myArrayField)) {
    db.collection.updateOne({ _id: docId }, { $push: { myArrayField: itemToAdd } });
  } else {
    // Handle cases where myArrayField is missing, null, or not an array
    console.warn(`myArrayField is not an array for document ${docId}. Skipping push.`);
    // Optionally, create the array if it's missing:
    // db.collection.updateOne({ _id: docId }, { $set: { myArrayField: [itemToAdd] } });
  }
});

3. Ensure Target Arrays Exist for $addToSet Operations medium

Explicitly create array fields if they don't exist before using $addToSet.

1
If you're using `$addToSet` and the array field might not exist on the document, MongoDB will not create it implicitly, leading to Error 21. You can use `$setOnInsert` with `$each` to initialize the array if the document is being inserted, or perform a separate `$set` operation to ensure the array exists before `$addToSet`.
const docId = 'new_or_existing_doc';
const itemToAdd = 'unique_item';

// Option 1: Use $setOnInsert for new documents (if applicable)
db.collection.updateOne(
  { _id: docId },
  { $setOnInsert: { myArrayField: [] } }, // Ensure array exists on insert
  { upsert: true } // Creates the document if it doesn't exist
);

// Then, perform the $addToSet operation (or combine if not upserting)
db.collection.updateOne(
  { _id: docId },
  { $addToSet: { myArrayField: itemToAdd } }
);

// Option 2: Explicitly create if missing (for existing documents)
db.collection.updateOne(
  { _id: docId, myArrayField: { $exists: false } },
  { $set: { myArrayField: [] } }
);
db.collection.updateOne(
  { _id: docId },
  { $addToSet: { myArrayField: itemToAdd } }
);

4. Review Application Logic for Array Handling advanced

Thoroughly inspect your application code that interacts with MongoDB arrays.

1
This error often stems from how your application constructs queries or updates. Look for instances where an array variable is passed to a MongoDB driver method (e.g., `find`, `updateOne`, `aggregate`) when that variable is `null`, `undefined`, or an empty array (`[]`) and the MongoDB operation expects a non-empty array.
// Example of problematic code in a Node.js application:
dynamicArray = getDynamicArray(); // This might return [] or null

// If dynamicArray is empty, this query will fail:
db.collection.find({ 'items.name': { $in: dynamicArray } });

// Corrected approach:
dynamicArray = getDynamicArray();
if (dynamicArray && dynamicArray.length > 0) {
  db.collection.find({ 'items.name': { $in: dynamicArray } });
} else {
  // Handle the empty array case gracefully.
  console.log('No items to search for.');
}
2
Pay close attention to data fetching and transformation logic. If data is being fetched from an external source or processed, ensure that array fields are handled correctly and consistently before being used in MongoDB operations.
text
🔗

Related Errors

5 related errors