An Elasticsearch index rejects writes with "Limit of total fields [1000] has been exceeded" — what happened and how do you fix it?
answer
- Data is being used as field names
- The mapping is not a local, cheap artefact
- One node applies every field addition
- Raising the number is treating the symptom
- Keys must become values to bound the count
basics
~20 sDynamic mapping turned unbounded data keys into permanent mapping entries and hit index.mapping.total_fields.limit, which defaults to 1000. Raising the limit is a stopgap; the fix is to stop the key space from becoming fields, using strict or scoped dynamic settings, templates, or a key/value structure.
solid answer
~50 sThis is mapping explosion. Something in the documents — user-defined attributes, per-customer keys, an object keyed by ID — is being turned into new mapping fields by `dynamic: true`, and the index hit `index.mapping.total_fields.limit` (default 1000). Note that each dynamically mapped string costs two entries, `field` and `field.keyword`. The mapping lives in cluster state, replicated to every node and updated through the master, so a huge mapping slows mapping updates, bloats cluster state and hurts recovery — raising the limit buys time and makes the eventual problem worse. The real fixes are structural: set `dynamic` to `strict` or `false` on the offending subtree, use dynamic templates so at least the types are controlled, or restructure the data so keys become *values* — an array of `{"key": ..., "value": ...}` objects, or a field type designed for arbitrary key spaces. Because fields cannot be removed from a mapping, cleaning up an already-exploded index means reindexing into a corrected one.
code
json · 9 lines// keys as field names: one new mapping entry per attribute
{ "sku": "A-1", "attrs": { "color": "red", "size": "XL", "strap_len_cm": 42 } }
// keys as values: two fixed fields no matter how many attributes exist
{ "sku": "A-1", "attrs": [
{ "k": "color", "v": "red" },
{ "k": "size", "v": "XL" },
{ "k": "strap_len_cm", "v": "42" }
]}go deeper
Recognise the error as too many distinct field names rather than too much data, and know the limit is a per-index setting with a default of 1000. Escalate rather than silently raising it.
Explain that dynamic mapping turned data keys into permanent fields, that each dynamic string costs a text field plus a keyword sub-field, and that fields cannot be removed without reindexing.
Handle it as an incident and a root cause: unblock writes, then constrain the subtree, restructure keys into key/value pairs, and reindex. Explain the cluster-state cost that makes an ever-larger mapping dangerous.
Decide the platform guardrails — per-tenant isolation, field-count alerting well below the cap, whether the contract is enforced at the ingest edge, and who owns approving a limit increase.
## What the error means Every index carries a mapping — the list of its fields and their definitions — and `index.mapping.total_fields.limit` caps how many entries it may contain. The default is **1000**. Field mappings, object mappings and field aliases all count toward it. When the cap is reached, any write that would create another field fails, which usually shows up as a wall of bulk-indexing errors rather than a gentle warning. ## How an index gets there Almost always, someone is using data as field names. The recognisable shapes: - a `custom_attributes` object whose keys are whatever a customer typed; - an object keyed by identifier — `by_user.{uuid}` — so every new entity mints a field; - metrics or feature flags emitted as `flags.<flag_name>: true`; - a multi-tenant index where each tenant contributes its own schema to a shared mapping; - an upstream that added an accidental field, such as a stack trace object exploded into per-frame keys. The rate is amplified by the dynamic string rule: a new string key produces both a `text` field and its `.keyword` sub-field, so the field budget drains twice as fast as the number of distinct keys suggests. ## Why the limit exists, and why raising it is not the fix A mapping is not a lightweight local artefact. It is part of the **cluster state**, which is held by the elected master and replicated to every node in the cluster. Every dynamic field creation is a cluster-state update: the write path pauses on the master to add the field, then the new state propagates. With many thousands of fields and a busy ingest stream, that update path becomes a bottleneck, master node heap grows, and node join and recovery slow because the state must be shipped and applied. There are per-field costs downstream too: `_source` mapping and query planning walk more fields, wildcard-field queries expand over more terms, and every field carries per-segment metadata. Bumping the limit to 5000 or 10000 will get writes flowing again — that is the right *incident* action — but it should be logged as an accepted risk with a follow-up, not treated as the resolution. Related caps you will meet in the same family: `index.mapping.depth.limit` (default 20) bounds nesting depth, and `index.mapping.nested_fields.limit` (default 50) bounds distinct `nested` fields per index. ## The structural fixes **Stop the subtree from creating fields.** Set `dynamic` to `false` or `strict` on the offending object. This can be applied to a live index with a mapping update, so it is available immediately. With `false`, existing documents keep their values in `_source` and stay retrievable; with `strict`, producers get a loud error instead. **Impose types with dynamic templates.** If new keys must be mapped, at least make them `keyword` only rather than `text` plus a sub-field. This halves the burn rate and removes the analysis cost; it does not bound the total. **Turn keys into values.** The durable fix is a schema change: instead of `{"attrs": {"color": "red", "size": "XL"}}`, index `{"attrs": [{"k": "color", "v": "red"}, {"k": "size", "v": "XL"}]}`. Now `attrs.k` and `attrs.v` are two fixed fields no matter how many attributes exist. If a key and its value must be matched together as a pair, that array needs a `nested` mapping, which has its own document-count cost — the trade is deliberate. **Isolate the tenants.** If the explosion comes from many tenants sharing one index, giving large or unpredictable tenants their own index bounds the blast radius: each mapping only carries one tenant's key space. **Expose the tail as runtime fields.** Data you must *occasionally* query but should not index can be reached with runtime fields, which read `_source` at query time and cost nothing in the mapping until you define them. ## Cleaning up an index that already exploded Mapping entries cannot be deleted. Reindex into a new index that has the corrected mapping — `dynamic` constrained, templates in place, the free-form data restructured by an ingest pipeline or a `_reindex` script — and cut over. Ship the corrected mapping in the index template first, so newly created indices stop reproducing the problem while you migrate the old ones. ## Detecting it before it pages you Field count per index is a monitorable number; alerting when an index crosses a fraction of its limit turns a hard write failure into a routine ticket. In time-based data the signal is even clearer: if today's index has many more fields than yesterday's, something upstream started emitting keys.
- Why is raising index.mapping.total_fields.limit only a stopgap?Because the mapping is part of cluster state, replicated to every node and updated through the elected master. Every dynamic field addition is a cluster-state update, so a very large mapping slows ingest, grows master heap, and lengthens node join and recovery. Raising the cap lets the growth continue toward those failures instead of stopping it.
- You have fixed the template, but the existing index still carries 4000 junk fields. How do you clean it up?You cannot remove fields from a mapping. Create a new index with the corrected mapping and reindex into it, reshaping the free-form data with an ingest pipeline or a reindex script, then swap the alias so readers move atomically. Fix the index template first so newly created indices stop reproducing the problem while the backfill runs.
- Why do dynamically mapped string fields consume the field budget faster than the key count suggests?Dynamic mapping gives a detected string both a `text` field and a `keyword` sub-field, and both are mapping entries against the limit. A dynamic template mapping detected strings to plain `keyword` halves the consumption and also removes analysis cost for data nobody full-text searches.
saying these in an interview costs you the question
- Says just raise the limit and moves on
- Believes unused mapping fields can simply be deleted
- Thinks the mapping is local to each shard
- Blames document count rather than distinct field names
- Assumes a bigger master node makes the problem go away