mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Selector must be a valid JavaScript object
Error message
Selector must be a valid JavaScript object
What it means
Thrown by makeUpdateStatement when the filter (selector) passed to update/updateOne/updateMany/replaceOne/findOneAnd* is null or not an object. The filter must be a JavaScript object (including {} for 'all'). Passing null, undefined, a string, number, or array triggers this MongoInvalidArgumentError client-side.
Source
Thrown at src/operations/update.ts:266
return {
acknowledged: this.writeConcern?.w !== 0,
modifiedCount: res.nModified ?? res.n,
upsertedId:
Array.isArray(res.upserted) && res.upserted.length > 0 ? res.upserted[0]._id : null,
upsertedCount: Array.isArray(res.upserted) && res.upserted.length ? res.upserted.length : 0,
matchedCount: Array.isArray(res.upserted) && res.upserted.length > 0 ? 0 : res.n
};
}
}
export function makeUpdateStatement(
filter: Document,
update: Document | Document[],
options: UpdateOptions & { multi?: boolean } & { sort?: Sort }
): UpdateStatement {
if (filter == null || typeof filter !== 'object') {
throw new MongoInvalidArgumentError('Selector must be a valid JavaScript object');
}
if (update == null || typeof update !== 'object') {
throw new MongoInvalidArgumentError('Document must be a valid JavaScript object');
}
const op: UpdateStatement = { q: filter, u: update };
if (typeof options.upsert === 'boolean') {
op.upsert = options.upsert;
}
if (options.multi) {
op.multi = options.multi;
}
if (options.hint) {
op.hint = options.hint;
}View on GitHub (pinned to 3366c21a63)
Solutions
- Pass a filter object, using {} to match all documents.
- Wrap ids: { _id: value } rather than the bare value.
- Default uninitialized filter variables to {} or validate they are objects before calling.
- If the filter is genuinely unknown, decide explicitly between {} (all) or no operation.
Example fix
// before
await collection.updateOne(maybeFilter, { $set: { x: 1 } }); // maybeFilter is undefined
// after
await collection.updateOne(maybeFilter ?? {}, { $set: { x: 1 } }); Defensive patterns
Strategy: type-guard
Validate before calling
function isFilterObject(f) {
return f != null && typeof f === 'object' && !Array.isArray(f);
}
if (!isFilterObject(filter)) throw new Error('filter must be a plain object (use {} for all)');
await collection.updateOne(filter, update); Type guard
function isFilterObject(f: unknown): f is Record<string, unknown> {
return f != null && typeof f === 'object' && !Array.isArray(f);
} Prevention
- Default filter variables to {} when they may be unset.
- Wrap ids as { _id: value }, never bare.
- Validate filters at the boundary of dynamic/config-driven code.
When it happens
Trigger: Calling collection.updateOne(null, ...) or updateOne(undefined, ...) because a variable holding the filter was not initialized; passing a primitive id directly (updateOne(5, ...)) instead of { _id: 5 }; passing an array where a filter object is expected.
Common situations: Uninitialized filter variables; refactoring that left a filter unset on some path; assuming an _id can be passed bare (it cannot - wrap in { _id: ... }); destructuring bugs producing undefined.
Related errors
- Update document requires atomic operators
- Bulk find operation must specify a selector
- Update document requires atomic operators
- Update document requires atomic operators
- Replacement document must not contain atomic operators
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/17720124aff6b438.json.
Report an issue: GitHub.