Download

The dollar ($) prefixed field is not valid for storage

An update put a name starting with $ where MongoDB expected a field name: an operator inside a replacement document, $set on a $-named field, or an aggregation expression in a classic update. Use the right update form, or $setField when the $ name is really data.

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

The dollar ($) prefixed field '$price' in '$price' is not allowed in the context of an update's replacement document. Consider using an aggregation pipeline with $replaceWith.

What it means

Names that start with $ are operators to MongoDB ($set, $inc, $cond). The server found one where a field name should be, in a place it won’t store it, and refused the write with code 52, DollarPrefixedFieldName.

The wording depends on the server version. Older servers said, as in this report on MongoDB’s forums:

The dollar ($) prefixed field '$cond' in 'energy.$cond' is not valid for storage.

MongoDB 8.0 says, for the cases that still fail:

The dollar ($) prefixed field '$price' in '$price' is not allowed in the context of an update's replacement document. Consider using an aggregation pipeline with $replaceWith.

Since 5.0, MongoDB can store field names that start with $, so some writes that used to fail now succeed, and that can be worse (see the third cause).

Common causes

  1. An operator inside a replacement. A raw update command, or a driver call that sends a replacement, with $set inside it: { qty: 3, $set: { a: 1 } }. Recent drivers catch the simple case first and say Replacement document must not contain atomic operators.
  2. $set or $rename with a top-level $ name: $set: { "$price": 5 }, often from user data whose keys weren’t checked.
  3. An aggregation expression in a classic update: $set: { status: { $cond: … } }. Older servers refused it with “not valid for storage”. MongoDB 8.0 accepts it and stores the $cond object as data, so the document gets status: { '$cond': [ … ] } instead of a value.
  4. Writing JSON from outside (a webhook payload, a MongoDB Extended JSON export) as a replacement or through $set, when some of its top-level keys start with $.

How to fix it

Use a pipeline when the new value is an expression

Wrap the update in an array. A pipeline update evaluates $cond, $concat, $ifNull and field references such as "$qty":

db.stock.updateOne(
  { _id: 1 },
  [{ $set: { status: { $cond: [{ $gt: ["$qty", 0] }, "in stock", "sold out"] } } }]
)

Keep operators and replacements apart

To change some fields, send only operators: { $set: { qty: 3, a: 1 } }. To replace the document, send a plain document with no $ keys (replaceOne). Don’t mix the two.

Clean the keys of outside data

If the keys come from users or other systems, rename those that start with $ (and those that contain .) before you store them, for example $price to price. That also keeps them queryable: $-prefixed fields can’t be indexed or checked by $jsonSchema.

If the $ name is data you must keep

Use $setField in a pipeline to write it, and $getField to read it:

db.stock.updateOne({ _id: 1 }, [
  { $replaceWith: { $setField: { field: { $literal: "$price" }, input: "$$ROOT", value: 5 } } }
])
db.stock.find({ $expr: { $eq: [{ $getField: { $literal: "$price" } }, 5] } })

Find documents that stored an expression by mistake

If a classic update stored $cond as data, find those documents and set the field again with a pipeline:

db.stock.find({ "status.$cond": { $exists: true } })

Reproduce it

MongoDB 8.0.32, mongosh 2.12.0, in a scratch database:

db.items.updateOne({ _id: 1 }, { $set: { "$price": 5 } })
MongoServerError: The dollar ($) prefixed field '$price' in '$price' is not allowed in the context of an update's replacement document. Consider using an aggregation pipeline with $replaceWith.

The error’s code was 52. A raw update command with { qty: 3, $set: { a: 1 } } returned the same code in writeErrors, naming '$set'. $rename: { qty: "$qty" } named '$qty'. Through mongosh’s replaceOne and findOneAndReplace, a replacement with $set in it never reached the server:

MongoInvalidArgumentError: Replacement document must not contain atomic operators

These were accepted: insertOne({ "$price": 5 }), a nested { meta: { "$price": 5 } }, and $set: { "meta.$price": 5 }. A classic update with an expression:

db.stock.updateOne({ _id: 1 }, { $set: { status: { $cond: [{ $gt: ["$qty", 0] }, "in stock", "sold out"] } } })
db.stock.findOne()
{
  _id: 1,
  qty: 3,
  status: { '$cond': [ { '$gt': [ '$qty', 0 ] }, 'in stock', 'sold out' ] }
}

The same $set as a pipeline stored status: 'in stock'. The $setField update added '$price': 5, and the $getField query found it. createIndex({ "$price": 1 }) was refused: Index key contains an illegal field name: field name starts with '$'.

In Inlet

Inlet’s document editor updates only the fields you edited and keeps each value’s type. Queries use mongosh syntax, so a pipeline update (db.stock.updateOne({ _id: 1 }, [{ $set: … }])) runs as it does in mongosh, and you can check the result in the inspector.

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