meteor/meteor · error · MiniMongoQueryError
unknown operator: ${unprefixedKeys[0]}
Error message
unknown operator: ${unprefixedKeys[0]} What it means
During upsert document inference, populateDocumentWithObject treats an object as a literal sub-document only if it has unprefixed keys or is empty. If it mixes unprefixed (literal) keys with '$'-prefixed operator keys, the first unprefixed key is reported as 'unknown operator' because operators are not allowed to coexist with literal fields in the inferred insert document.
Source
Thrown at packages/minimongo/common.js:1240
function populateDocumentWithKeyValue(document, key, value) {
if (value && Object.getPrototypeOf(value) === Object.prototype) {
populateDocumentWithObject(document, key, value);
} else if (!(value instanceof RegExp)) {
insertIntoDocument(document, key, value);
}
}
// Handles a key, value pair to put in the selector document
// if the value is an object
function populateDocumentWithObject(document, key, value) {
const keys = Object.keys(value);
const unprefixedKeys = keys.filter(op => op[0] !== '$');
if (unprefixedKeys.length > 0 || !keys.length) {
// Literal (possibly empty) object ( or empty object )
// Don't allow mixing '$'-prefixed with non-'$'-prefixed fields
if (keys.length !== unprefixedKeys.length) {
throw new MiniMongoQueryError(`unknown operator: ${unprefixedKeys[0]}`);
}
validateObject(value, key);
insertIntoDocument(document, key, value);
} else {
Object.keys(value).forEach(op => {
const object = value[op];
if (op === '$eq') {
populateDocumentWithKeyValue(document, key, object);
} else if (op === '$all') {
// every value for $all should be dealt with as separate $eq-s
object.forEach(element =>
populateDocumentWithKeyValue(document, key, element)
);
}
});
}View on GitHub (pinned to 5076d2f818)
Solutions
- Do not mix literal and operator keys in a single equality value; split across fields or use $and.
- Provide an explicit upsert insert document.
- Restructure the selector so equality values are either fully literal or fully operator objects.
Example fix
// before
coll.update({ a: { b: 1, $gt: 0 } }, { $set: { x: 1 } }, { upsert: true });
// after
coll.update({ $and: [{ 'a.b': 1 }, { a: { $gt: 0 } }] }, { $set: { x: 1 } }, { upsert: true }); Defensive patterns
Strategy: validation
Validate before calling
function isPureObjectValue(obj) {
if (!obj || typeof obj !== 'object') return true;
const keys = Object.keys(obj);
const ops = keys.filter(k => k[0] === '$');
const literals = keys.filter(k => k[0] !== '$');
return ops.length === 0 || literals.length === 0;
} Type guard
function isMixedKeyObject(obj) {
if (!obj || typeof obj !== 'object') return false;
const keys = Object.keys(obj);
return keys.some(k => k[0] === '$') && keys.some(k => k[0] !== '$');
} Prevention
- Never merge a literal object and an operator object into one equality value for upsert.
- Provide explicit upsert insert documents when value shapes are dynamic.
- Run isPureObjectValue on equality values before upserting.
When it happens
Trigger: An upsert equality clause whose value object mixes literal and operator keys, e.g. update({a: {b: 1, $gt: 0}}, ..., {upsert: true}). The upsert path tries to store 'a' as a literal {b:1,$gt:0} which is illegal.
Common situations: Building equality values by merging a literal object and an operator object into one, then upserting. Less common than 227 because this specifically concerns upsert insert-document inference.
Related errors
- Unrecognized logical operator: ${key}
- Can't create equalityValueSelector for operator object
- cannot infer query fields to set, both paths '${existingKey}
- cannot infer query fields to set, path '${key}' is matched t
- Inconsistent operator: ${JSON.stringify(valueSelector)}
AI-assisted analysis of meteor/meteor@5076d2f818 (2026-08-13).
Data as JSON: /api/errors/b89863b633958f76.
Report an issue: GitHub.