Pulse 2025 Product Roundup: From Monitoring to AI-Native Control Plane

Read more

Elasticsearch Mapping Type Conflict

Elasticsearch locks a field's data type the moment it appears in an index mapping. Send a string to a field that was already mapped as long and the document gets rejected with a mapper_parsing_exception. The same class of problem surfaces when you search across indices that disagree on what type a field should be. This article breaks down why these conflicts happen, what the error messages actually tell you, and how to get out of the mess.

How Type Conflicts Arise

Every Elasticsearch index maintains its own mapping. When dynamic mapping is enabled (the default), the type assigned to a field depends on the first document that contains it. If index logs-2025.01 receives {"status": 200}, the status field becomes long. If logs-2025.02 receives {"status": "OK"}, that same field name becomes text. Neither index has an internal conflict - the problem appears the moment you query both at once.

This commonly happens with log data from multiple sources. One application emits a JSON numeric error_code, another emits it as a string. Time-based indices created without a shared index template will silently diverge. Teams that rely entirely on dynamic mapping are the most exposed, since the type depends on the shape of whichever document arrives first after index creation.

Anatomy of the Error

When you index a document with a mismatched type within a single index, Elasticsearch returns a mapper_parsing_exception:

{
  "error": {
    "type": "mapper_parsing_exception",
    "reason": "failed to parse field [status] of type [long] in document with id '5kxJ...'",
    "caused_by": {
      "type": "illegal_argument_exception",
      "reason": "For input string: \"OK\""
    }
  },
  "status": 400
}

The reason line tells you the field name, the expected type, and which document triggered the failure. The caused_by block gives you the raw parse error. When the conflict is across indices rather than within one, you won't see a rejection at index time. Instead, searches and aggregations against a wildcard pattern like logs-* return partial results or throw a different error - Kibana surfaces this as a "Mapping conflict" warning in the index pattern configuration.

You can check for cross-index conflicts by comparing the mappings directly:

GET /logs-*/_mapping/field/status

If the response shows long in one index and text in another, you have a cross-index type conflict.

Prevention With Explicit Mappings and Index Templates

The cleanest fix is to never let the conflict happen. Define your mappings explicitly through composable index templates so every new index in a series uses the same field types.

PUT _index_template/logs-template
{
  "index_patterns": ["logs-*"],
  "template": {
    "mappings": {
      "dynamic": "strict",
      "properties": {
        "status": { "type": "keyword" },
        "response_time_ms": { "type": "float" },
        "@timestamp": { "type": "date" }
      }
    }
  },
  "priority": 200
}

Setting dynamic to strict rejects any document that contains unmapped fields, which eliminates surprise type assignments. If you need more flexibility, use dynamic: false instead - unknown fields will be stored in _source but not indexed. Component templates let you share field definitions across multiple index templates so teams don't re-invent field types independently.

For indices that already exist with the wrong mapping, the only path is reindexing. Create a new index with the correct mapping, then use the Reindex API:

POST _reindex
{
  "source": { "index": "logs-2025.01" },
  "dest": { "index": "logs-2025.01-fixed" }
}

If the source data contains values that can't be coerced to the target type, those documents will be rejected during reindex. Add "conflicts": "proceed" to skip them and handle failures afterward.

The ignore_malformed Escape Hatch

When reindexing isn't practical - say you have terabytes of time-series data and can only fix things going forward - ignore_malformed lets the index silently drop unparseable values for a field instead of rejecting the whole document:

PUT /logs-2025.03
{
  "mappings": {
    "properties": {
      "status": {
        "type": "long",
        "ignore_malformed": true
      }
    }
  }
}

With this setting, a document where status is "OK" will still be indexed, but the status field won't be searchable or aggregatable for that document. The original value remains in _source. You can also enable it index-wide with index.mapping.ignore_malformed: true in settings.

There are limits. ignore_malformed only works for scalar type mismatches - it won't save you if a field is mapped as keyword and you send a JSON object. That case still throws a mapper_parsing_exception regardless of the setting.

Runtime Fields as a Query-Time Override

Runtime fields let you redefine a field's type at query time without reindexing. If status is long in some indices and text in others, you can paper over the conflict in a search request:

GET /logs-*/_search
{
  "runtime_mappings": {
    "status_normalized": {
      "type": "keyword",
      "script": {
        "source": "emit(String.valueOf(doc['status'].value))"
      }
    }
  },
  "query": {
    "term": { "status_normalized": "200" }
  }
}

This approach works for searches and aggregations that cross index boundaries with conflicting types. The trade-off is performance - runtime fields are computed on every query, so they're slower than indexed fields. For dashboards that run frequently, consider materializing the fix through reindexing or adding the runtime field to the index mapping permanently so it gets computed once per document rather than once per query.

Runtime fields defined in the index mapping also work well as a bridge during migration. You can add the runtime field, update dashboards to use it, then reindex at your own pace and swap the runtime field for a standard indexed field later.

Pulse - Elasticsearch Operations Done Right

Pulse can solve your Elasticsearch issues

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.