Logit.io
Fix the producer before rebuilding the index
← Back to blog
10/22/2026 · 7 min read

Don't delete the index to fix OpenSearch field type conflicts

Logit.io Team
Logit.io Team
Technical Content Team

Last updated 10/22/2026

OpensearchLogstashHow To Guides

A mapper_parsing_exception saying failed to parse field [status] of type [long] makes deleting the index look like the quick fix. The next index starts clean, ingestion resumes and the dashboard recovers, until the same shipper sends the same incompatible value again.

Before you delete anything, find out which producer is changing the field's type. On Hosted OpenSearch, the lasting fix is to make that type consistent before indexing. Reindexing can repair history afterwards, but it can't correct tomorrow's input.

Contents

A rejected document is missing data

Consider this illustrative pair of events, sent to an index with no existing mapping for status:

{"service":"gateway","status":200}
{"service":"worker","status":"OK"}

If the integer establishes a long mapping, the later "OK" cannot be parsed as that number. The document is rejected, rather than indexed with just its awkward field removed. Error wording can include mapper_parsing_exception or, on some systems, document_parsing_exception; follow the field and cause rather than matching one exception name.

Deleting the index destroys searchable evidence and gives the producers another race to define the field. Keep the rejection, its destination index and the original event. You need those to distinguish a bad value from a bad field contract.

The first value wins only for unmapped fields

With dynamic mapping, the first value OpenSearch can map establishes an unknown field's type. Explicit mappings and matching dynamic templates take precedence, so a new daily index is not necessarily a blank slate.

The OpenSearch 3.3 mapping rules map JSON integers to long. Date detection is enabled by default; matching strings can become dates. Numeric detection is disabled by default, so quoting a number does not automatically create a numeric mapping. These are upstream defaults, not a statement of your managed stack's overrides.

Detection and coercion are different. Once a numeric mapping exists, coercion is enabled by default, allowing a value such as "5" into a long. That does not make "OK" numeric. Check the actual mapping before concluding that every quoted number causes rejection.

Mixed status values race to establish a mapping and cause rejections; splitting and converting in Logstash gives the next index consistent types

Bulk success can hide item failures and older conflicts

A successful HTTP request does not prove every event arrived. The Bulk API response has an errors flag and an items array. Inspect each failed operation's status and error, including its reason and destination index. Other items can succeed in the same batch.

Look in the Logstash output logs too. The Elasticsearch output drops document-level 400 and 404 errors after logging them unless a dead letter queue is enabled. The OpenSearch output plugin behaves similarly; check your plugin version and DLQ configuration.

A Dashboards index pattern marked conflict is a separate clue: its matching indices disagree about a field's type. Today's index may accept everything while yesterday's maps status as text. Refreshing the field list cannot rewrite those mappings. The Logit docs on mapping conflicts walk through spotting them in Dashboards.

Follow the field back to the shipper

Use the rejected item's exact index first, then compare the daily indices covered by the dashboard. These Dev Tools requests keep the investigation on one field:

GET /logs-example-2026.10.22/_mapping/field/status
GET /logs-example-2026.10.21/_mapping/field/status
GET /logs-example-*/_field_caps?fields=status

The field capabilities response groups entries under fields, then field name, then type. When types differ, each type's indices array identifies its indices. This separates a single write-index rejection from a pattern spanning incompatible mappings.

Now compare the rejected payload with an accepted event from each source. Follow service names, input tags, shipper configuration and parser branches. A JSON decoder may preserve a number while a grok capture leaves a string; a worker may use the same name for a human-readable state. Inspect the event after filters as well as the application's raw line, because the pipeline may introduce the mismatch.

Start by turning on the dead letter queue. On a Logit stack, enable DLQ in the stack's Advanced Stack Settings, and rejected events land in a dlq-* index you can open in Discover. Each entry carries dead_letter_queue_reason, which names the field and type that failed, and original_data, the payload as it arrived. See Logstash dead letter queue for the setup. Once you can see the rejected payloads, compare the output warning with source-side samples, and trace the route into the destination index. Check whether an older agent configuration or a second pipeline still writes the original field. Fixing one parser branch leaves the race intact if another route bypasses it.

Give each meaning a deterministic type in Logstash

If a field means a numeric code everywhere, normalise validated values using mutate { convert => }. If it means two different things, split it. For the scalar status values above, this filter stringifies the input before applying a regex, then separates codes from labels:

filter {
  if [status] {
    mutate { convert => { "status" => "string" } }
    if [status] =~ /^\d+$/ {
      mutate { rename => { "status" => "status_code" } }
      mutate { convert => { "status_code" => "integer" } }
    } else {
      mutate { rename => { "status" => "status_text" } }
    }
  }
}

The string conversion makes the regex safe for the example's integer and string inputs. The digit-only branch deliberately excludes negatives and decimals because these are status codes. It is not a general numeric validator: check range separately and define handling for objects, arrays and empty values before adapting it to other fields.

The mutate reference documents conversion and rename behaviour. Separate blocks make the sequence explicit. Reserve the destination names for this contract across every producer; an existing conflicting status_code mapping still needs a fresh index. No Ruby filter is needed here.

Test both example events through the edited pipeline, inspect the output types, then send them to a disposable custom index. Verify the mapping and both documents. Also test a deliberately invalid input and confirm where it goes. Keep replayable source data, because fixing filters does not recover documents already dropped.

Repair history without repeating the race

On Logit.io managed stacks, mappings and templates are read-only, as the managed stack limitations explain. Fix the input in Logstash and take managed template changes to support. For your own custom index, the index APIs let you supply explicit mappings when creating it:

PUT /my-status-clean-000001
{
  "mappings": {
    "properties": {
      "status_code": {"type":"long"},
      "status_text": {"type":"keyword"}
    }
  }
}

You cannot change an existing field's type in place. After correcting input and checking inherited mappings, wait for the next scheduled daily or rollover index if historical inconsistency is tolerable. Otherwise reindex the specific affected index into a new one with corrected mappings and an appropriate transformation (see the Logit guide to reindexing). Reindexing does not run your Logstash filters automatically.

Make the acceptance check cover the next index boundary as well. Confirm that the fresh index inherits the mapping you intended, then compare source event counts with successful writes and rejected items over the same interval. A quiet output log is useful evidence, but it does not establish that every producer has exercised its less common error path. Include those payloads in the test fixtures.

Verify reads before switching them. Old indices keep the cross-index conflict while the pattern includes them, until they age out under your retention and ISM plan or are deliberately excluded. Reindexing also cannot recover rejected documents that never arrived. For a different mapping failure involving too many field names, see the sibling post on mapping explosion and field limits.

Migration moves type decisions earlier

Teams coming from Splunk's search-time extraction or Datadog's flexible log search can expect mixed values to “just work”. That expectation needs qualification: Datadog facets and measures have types too. OpenSearch's schema-on-write mapping makes incompatible input a possible ingestion failure, rather than merely a later analysis problem.

Include representative mixed inputs in your Datadog migration or Splunk migration tests. Use the Hosted OpenSearch overview and OpenSearch pricing when planning the destination. Before moving the next stream, agree which producer owns each shared field's meaning and verify that every parser emits its agreed type.

Start Free Trial

Unlock complete visibility with hosted ELK, Grafana, and Prometheus-backed Observability

Start Free Trial

Get the latest Elastic Stack & logging resources when you subscribe

Want to see this in action?
Start a free trial and connect logs to your alert workflows.