Download

text index required for $text query

A $text search only works on a collection with a text index, and this one has none. Create a text index on the fields to search (one per collection, covering all of them), or use $regex for simple pattern matches.

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

text index required for $text query

What it means

$text searches words in string fields, with stemming (“index” finds “indexing”) and a relevance score. It doesn’t scan documents: it reads a text index. When the collection has no text index, MongoDB refuses the query with code 27, IndexNotFound, and this message. The same happens inside an aggregation’s $match.

A collection can have only one text index, but it can cover several fields, or every string field with a wildcard.

Common causes

  1. The index was never created on this server: it exists in development but not in production, or the code that creates it (Mongoose’s autoIndex, a migration) didn’t run.
  2. The wrong collection or database, for example a misspelt name or a collection created by a test. A collection that doesn’t exist has no indexes.
  3. The index was dropped, perhaps to replace it, and the new one wasn’t created.
  4. Expecting Atlas Search. $text uses the database’s own text index; Atlas Search is a separate feature queried with the $search aggregation stage and its own search index.

How to fix it

Check the indexes

db.articles.getIndexes()

A text index shows key: { _fts: "text", _ftsx: 1 } and its fields in weights.

Create a text index

List every field the search should cover in one index:

db.articles.createIndex({ title: "text", body: "text" })

Or cover every string field: db.articles.createIndex({ "$**": "text" }). Weights make matches in some fields count more: { weights: { title: 5, body: 1 } } as the second argument. Building the index reads the whole collection, so on a large one, create it at a quiet time.

Search, sorted by relevance

db.articles.find(
  { $text: { $search: "index" } },
  { title: 1, score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })

Replace the text index to change its fields

A second text index is refused (see index already exists). Drop the old one by name, then create the new one:

db.articles.dropIndex("title_text_body_text")
db.articles.createIndex({ title: "text", body: "text", summary: "text" })

Or use $regex for simple matches

For a substring or prefix match on one field, $regex needs no text index:

db.articles.find({ title: { $regex: "index", $options: "i" } })

It doesn’t stem words or rank results, and only an anchored, case-sensitive pattern (/^Index/) uses an ordinary index on the field efficiently.

Reproduce it

MongoDB 8.0.32, mongosh 2.12.0, two articles and no text index:

db.articles.find({ $text: { $search: "index" } })
MongoServerError[IndexNotFound]: text index required for $text query

The error’s code was 27. An aggregation with $match: { $text: … } gave the same message. After createIndex({ title: "text", body: "text" }) (named title_text_body_text), the search found “Indexing in MongoDB” with a score of 1.35. A second text index on summary was refused:

MongoServerError[IndexOptionsConflict]: An equivalent index already exists with a different name and options. Requested index: { v: 2, key: { _fts: "text", _ftsx: 1 }, name: "summary_text", … }, existing index: { v: 2, key: { _fts: "text", _ftsx: 1 }, name: "title_text_body_text", … }

The $regex query with $options: "i" found the same article without a text index.

In Inlet

Queries use mongosh syntax, so db.articles.getIndexes() shows what the collection has, and createIndex and the $text search run as they do in mongosh.

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