LEARN · DEBUGGING GUIDE

Elasticsearch Mapping Conflict Error: Diagnosis & Fix

Mapping conflicts in Elasticsearch arise when the same field is indexed with different types across documents or indices. This guide shows you exactly how to identify, fix, and prevent them.

IntermediateSearch7 min read

What this usually means

Mapping conflicts occur when Elasticsearch encounters a field with a data type that contradicts an existing mapping for the same field in the same index. This often happens with dynamic mapping enabled—when a new document introduces a field with a type different from what was previously seen. Another common cause is index templates that define a field as one type (e.g., 'keyword') while an ingested document sends it as another (e.g., 'text'). The conflict can also arise across indices in a multi-index search pattern if field mappings are not aligned. The error is Elasticsearch's way of saying 'I cannot store this document because the mapping is inconsistent'—it's a strict schema enforcement mechanism that prevents data corruption.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Run 'GET /_cat/indices?v' to list indices and identify which index has the error from application logs.
  • 2Check the exact error message in application logs or from a failed request: it includes the field name and conflicting types.
  • 3Inspect the current mapping of the affected index: 'GET /<index>/_mapping'. Look for the field in question.
  • 4Check the dynamic mapping settings: 'GET /<index>/_settings' and look for 'dynamic' setting (true/false/strict).
  • 5Review index templates that apply to this index pattern: 'GET /_template/<template-name>' to see if they force a type.
  • 6If using multi-index search, compare mappings across all indices in the alias or pattern: 'GET /<pattern>*/_mapping'.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchApplication logs: search for 'mapper_parsing_exception' or 'illegal_argument_exception' with field name.
  • searchElasticsearch server logs (usually in /var/log/elasticsearch/): look for 'MappingConflict' or 'field [...'
  • searchIndex mapping API: 'GET /<index>/_mapping' to see the current schema.
  • searchIndex settings: 'GET /<index>/_settings' to check dynamic mapping mode.
  • searchIndex templates: 'GET /_template/*' or 'GET /_template/<pattern>' to see pre-defined mappings.
  • searchField capabilities API: 'GET /<index>/_field_caps?fields=*' to see field types across indices.
  • searchPipeline configuration: if using ingest pipelines, check if they modify field types.
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningDynamic mapping creates a field as 'text' first, then a later document sends the same field as 'keyword' (or integer, etc.).
  • warningIndex template defines a field as 'keyword' but data source sends it as 'text' with a full-text search expectation.
  • warningSame field name used for different purposes across time (e.g., 'status' was a string, now an integer).
  • warningMulti-index search (e.g., logs-*) where one index has field 'response_time' as 'float' and another as 'integer'.
  • warningReindex operation from an index with 'strict' dynamic mapping to a target with different mappings.
  • warningLogstash or Beats configuration that sends a field with inconsistent types due to parsing errors.
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildUpdate the index template to explicitly define the field type and set 'dynamic': 'strict' to prevent accidental new fields.
  • buildIf conflict is from dynamic mapping, reindex the affected index with explicit mapping: create a new index with correct mapping and use reindex API.
  • buildFor existing data with mixed types, use a scripted update or reindex to coerce values to a common type (e.g., convert all to 'keyword').
  • buildSet 'dynamic': 'false' on the index to ignore unmapped fields (they won't be indexed but will be stored in _source).
  • buildUse a pipeline with a 'convert' processor to transform field types before indexing.
  • buildIf using multi-index pattern, apply same mapping template to all indices and reindex those that differ.
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedAfter fix, run a test index request with the previously failing data and confirm 201/200 response.
  • verifiedQuery the index mapping again: 'GET /<index>/_mapping' and verify the field type is consistent.
  • verifiedCheck that aggregations on the field now work: 'POST /<index>/_search { "aggs": {"test": {"terms": {"field": "<field>"}}} }'
  • verifiedRun the original search query that triggered the error and confirm no exceptions.
  • verifiedCheck cluster health: 'GET /_cluster/health' and ensure no red indices.
  • verifiedIf using reindex, verify document count matches and run a sample query to compare results.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningDeleting the old index before confirming the new mapping works (you lose data).
  • warningSetting 'dynamic': true on production indices—prefer 'strict' or 'false' after schema stabilizes.
  • warningIgnoring the conflict and retrying the same request—it will fail again.
  • warningUsing 'ignore_malformed' to bypass type errors (it only works for malformed JSON, not type mismatches).
  • warningManually updating mapping on an existing field (Elasticsearch does not allow changing type of existing fields).
  • warningAssuming all fields from different sources have same type without verifying source schemas.
( 07 )War story

The Case of the Fluctuating Response Time Field

Platform Engineer at a SaaS companyElasticsearch 7.17, Logstash 7.17, custom Java app, Kibana 7.17

Timeline

  1. 09:15PagerDuty alert: 'search latency increased' for customer-facing dashboard
  2. 09:20Check Kibana, see 'field [response_time] of type [long] does not match existing field of type [float]' in logs
  3. 09:25Run 'GET /logs-2023.10.05/_mapping' and find 'response_time' as 'long' in one shard
  4. 09:30Check index template 'logs-template' - defines 'response_time' as 'float'
  5. 09:35Discover a new microservice sending response_time as integer (whole seconds) instead of float (milliseconds)
  6. 09:40Create new index 'logs-2023.10.05-v2' with correct mapping (float) and set 'dynamic': 'strict'
  7. 09:45Reindex data from 'logs-2023.10.05' to 'logs-2023.10.05-v2' with a script converting integer to float
  8. 09:50Update alias 'logs-write' to point to new index, delete old index
  9. 09:55Fix microservice to send float value, add pipeline to convert if needed
  10. 10:00Verify dashboards load correctly, latency returns to normal

The morning started with a PagerDuty alert for increased search latency on our customer-facing dashboard. I jumped into Kibana and quickly spotted the error: 'field [response_time] of type [long] does not match existing field of type [float]'. This was a classic mapping conflict. Our logs index had a dynamic mapping that created a float field for response_time, but some new documents were sending it as an integer.

I checked the index template 'logs-template' and confirmed it defined response_time as a float. But the dynamic mapping had already created the field as float in the index, so when a document with an integer came in, Elasticsearch rejected it. I traced the source to a new microservice that was sending response_time in whole seconds (integer) instead of milliseconds (float). The fix required reindexing the affected index with the correct mapping and updating the microservice.

I created a new index with explicit mapping and dynamic set to strict, then reindexed the old data using a script to convert any integers to floats. After updating the alias and deleting the old index, the dashboards worked. I also added an ingest pipeline to catch future mismatches. The lesson: always define explicit mappings in templates and set dynamic to strict in production to avoid these surprises.

Root cause

A new microservice sent response_time as an integer (long) while the existing mapping defined it as float, causing a mapping conflict error.

The fix

Reindexed the affected index to a new index with correct float mapping and strict dynamic setting. Updated the microservice to send float values and added an ingest pipeline for type coercion.

The lesson

Use explicit field mappings in index templates and set dynamic to 'strict' (or 'false') in production to prevent mapping conflicts from unexpected data types.

( 08 )Understanding Dynamic Mapping and Type Coercion

Elasticsearch infers field types from the first document indexed. If a field appears as a string, it becomes 'text' (plus a 'keyword' sub-field). Subsequent documents with the same field but different type (e.g., integer) cause a mapping conflict. This is by design—Elasticsearch cannot change the type of an existing field because that would invalidate the inverted index.

Dynamic mapping has three modes: 'true' (default, new fields added dynamically), 'false' (ignore new fields, not indexed but stored in _source), and 'strict' (reject documents with new fields). For production, 'strict' is recommended after schema stabilization to catch unexpected fields early.

( 09 )How to Fix Without Reindexing (Spoiler: You Can't)

There is no way to change the type of an existing field in Elasticsearch. The only solution is to create a new index with the correct mapping and reindex the data. Use the reindex API to copy documents, optionally with a script to transform field values. If you have a large dataset, consider using reindex with slicing for parallelism.

Alternatively, if the conflict is only in a small number of documents, you can delete those documents and re-ingest them with the correct type. But reindexing is safer and more complete.

( 10 )Preventing Mapping Conflicts with Index Templates and Pipelines

Index templates define mappings and settings for indices matching a pattern. Always create a template for your index pattern (e.g., 'logs-*') that explicitly defines field types. Set 'dynamic': 'strict' in the template to reject unknown fields. Example: 'PUT /_template/logs-template { "index_patterns": ["logs-*"], "mappings": { "dynamic": "strict", "properties": { "response_time": { "type": "float" } } } }'.

Ingest pipelines can also transform field types before indexing. Use the 'convert' processor to change a field from one type to another. This is useful when you cannot control the data source. Example: 'PUT /_ingest/pipeline/convert-response-time { "processors": [ { "convert": { "field": "response_time", "type": "float", "ignore_missing": true } } ] }'.

( 11 )Debugging Multi-Index Mapping Conflicts

When searching across multiple indices (e.g., 'logs-*'), a conflict can occur if the same field has different types in different indices. To find these, use the field capabilities API: 'GET /logs-*/_field_caps?fields=response_time'. It will show the types across all matching indices. You can then reindex the offending indices to align types.

Another approach is to use 'search_type=dfs_query_then_fetch' which does a pre-search to collect term statistics, but it does not resolve mapping conflicts. The fix is always to make mappings consistent.

Frequently asked questions

Can I change a field type after index creation without reindexing?

No. Elasticsearch does not allow changing the type of an existing field because the inverted index is built based on the original type. You must create a new index with the correct mapping and reindex the data. Use the reindex API with a script if you need to transform values.

What is the difference between 'dynamic': true, false, and strict?

When 'dynamic' is 'true' (default), new fields are detected and added to the mapping automatically. 'false' ignores new fields—they are stored in _source but not indexed, so you cannot search on them. 'strict' rejects any document containing a field not in the mapping. Use 'strict' in production to prevent accidental schema changes.

How do I find which field is causing the mapping conflict?

The error message from Elasticsearch includes the field name and the conflicting types. For example: 'field [response_time] of type [long] does not match existing field of type [float]'. You can also inspect the index mapping with 'GET /<index>/_mapping' to see the current types.

Can I use 'ignore_malformed' to solve mapping conflicts?

No. 'ignore_malformed' only applies to malformed JSON data (like a string where a number is expected). It does not prevent mapping conflicts caused by type mismatches. For type mismatches, you need to either convert the data or reindex.

What happens if I have a mapping conflict in a multi-index search?

The search will fail with an error stating the conflicting field and types. You must make the field type consistent across all indices in the search pattern. Use the field capabilities API to identify mismatched indices and reindex them to align types.