Download

unknown operator: $…

Your query filter contains a $ name MongoDB doesn’t know as a query operator: a typo ($regx, $exist), the wrong case ($Lt), one from SQL or another database ($like, $contains), or an aggregation expression used without $expr.

MongoDB error 2· Tested on MongoDB 8.0.32 (mongosh 2.12.0)· Updated 11 October 2026

unknown operator: $foo

What it means

In a filter, a name that starts with $ must be a query operator: $eq, $gt, $in, $exists, $regex, $and, $or and so on. MongoDB found one it doesn’t know and refused the query with code 2, BadValue. Nothing ran.

Where the name sits decides the wording:

  • unknown operator: $foo: inside a field’s condition, as in { qty: { $foo: 1 } }.
  • unknown top level operator: $foo. If you have a field name that starts with a '$' symbol, consider using $getField or $setField.: at the top of the filter, as in { $foo: 1 }.

The same applies to find, countDocuments, deleteMany, the filter of an update, and $match in an aggregation.

Common causes

  1. A typo or the wrong case: $regx, $exist, $Lt. Operators are case-sensitive.
  2. An operator from another language or database: $like (SQL’s LIKE), $contains, $between, $ilike.
  3. An aggregation expression in a plain filter. { $eq: ["$qty", "$count"] } compares two fields only inside $expr; at the top level it’s an unknown operator.
  4. User input passed into the filter as an object. A query-string parser that reads brackets turns ?name[$foo]=x into { name: { $foo: "x" } }. That also means users can inject real operators such as $ne, which is worse.
  5. A field name that really starts with $, which MongoDB reads as an operator.

How to fix it

Use the real operator

You wroteUse
$regx, $like, $contains{ name: { $regex: "amp", $options: "i" } } or { name: /amp/i }
$exist{ qty: { $exists: true } }
$Lt, $GTE$lt, $gte
$between{ qty: { $gte: 1, $lte: 10 } }
$ne on several values$nin: [ … ]

A $regex without a leading ^ can’t use an index efficiently, so prefer anchored patterns (/^amp/) or a text index for word search.

Compare fields with $expr

To compare one field with another, or use aggregation expressions in a filter:

db.p.find({ $expr: { $eq: ["$qty", "$count"] } })

Don’t pass request objects into filters

Cast inputs to the type you expect before they reach the query (String(req.query.name)), or validate them with a schema. Mongoose’s sanitizeFilter option wraps such objects in $eq, so they’re compared as values instead of being read as operators.

Read a field whose name starts with $

db.p.find({ $expr: { $eq: [{ $getField: { $literal: "$price" } }, 5] } })

Reproduce it

MongoDB 8.0.32, mongosh 2.12.0:

db.items.find({ qty: { $foo: 1 } })
MongoServerError[BadValue]: unknown operator: $foo

The error’s code was 2 and its codeName BadValue. With the operator at the top:

db.items.find({ $foo: 1 })
MongoServerError[BadValue]: unknown top level operator: $foo. If you have a field name that starts with a '$' symbol, consider using $getField or $setField.

$like, $contains, $exist, $regx and $Lt (beside a valid $gt) each gave unknown operator: <name>. { $eq: ["$qty", "$count"] } gave unknown top level operator: $eq, and the same comparison inside $expr ran. A related mistake gave its own message with the same code:

MongoServerError[BadValue]: Failed to parse $size. Expected a number in: $size: { $gt: 0 }

That came from { tags: { $size: { $gt: 0 } } }: $size takes only an exact number. Use { "tags.0": { $exists: true } } for “at least one element”.

With Mongoose 8.23.0, a schema path caught { name: { $foo: "x" } } before it was sent: Error: Can't use $foo with String. With sanitizeFilter on, the same filter, and one with $ne, failed as a CastError instead, since the object was now a value.

In Inlet

Queries use mongosh syntax, so you can try the corrected filter in a query tab before you change your code. Filters in Inlet’s grid run on the server, and a refused query shows the server’s message with the operator it didn’t know.

Inlet: a database client for the Mac

One native app for PostgreSQL, MySQL, SQL Server, SQLite, MongoDB and Redis. It explains errors where they happen, holds your edits until you save them, and keeps production read-only until you say so.

Version 0.1.0 · macOS 26 Tahoe or later · Apple silicon and Intel