Logstash Error Guide: 'Could not index event to Elasticsearch ... mapper_parsing_exception' — Fix the Type Conflict
Fix Logstash 'Could not index event to Elasticsearch ... mapper_parsing_exception': coerce field types, control dynamic mapping, and capture rejects in the DLQ.
- #logstash
- #logging
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
Elasticsearch enforces a mapping per index: once a field has a type, every later document must supply a value that fits that type. When Logstash sends an event whose field doesn’t match the established mapping, the elasticsearch output logs the per-document rejection and moves on:
[WARN ][logstash.outputs.elasticsearch] Could not index event to Elasticsearch.
{:status=>400, :action=>["index", {:_id=>nil, :_index=>"app-logs-2026.07.11",
:routing=>nil}, {...}], :response=>{"index"=>{"error"=>{
"type"=>"mapper_parsing_exception",
"reason"=>"failed to parse field [response_time] of type [long] in document with id 'abc123'.
Preview of field's value: '12.5ms'",
"caused_by"=>{"type"=>"illegal_argument_exception",
"reason"=>"For input string: \"12.5ms\""}}}}}
This is a non-retryable 400: retrying the same document produces the same error forever, so the event is dropped (or sent to the dead letter queue if enabled). The reason names the exact field, its mapped type, and a preview of the offending value — that line is the whole diagnosis.
Symptoms
Could not index event to Elasticsearchwith"type"=>"mapper_parsing_exception"and:status=>400inlogstash-plain.log.- The
reasonnames a specific field and a type mismatch (a string where along/date/ipis mapped, an object where a scalar is mapped, or vice versa). - Events from one log source index fine while a different source silently disappears from Kibana.
- The DLQ grows steadily (if enabled) or event counts don’t add up (if not).
- Errors began right after a new log format, a code change, or a new field started flowing.
Common Root Causes
- Type conflict across sources — the first document to create the field fixed its type; a later source sends a different type (e.g.
statusas200then"200",response_timeas12then"12.5ms"). - String where a number/date/ip is mapped — a unit suffix (
ms,kb), a placeholder ("-","N/A","null"), or an unparsed value reaching a numeric/date/ip field. - Object vs. scalar collision — a field arrives as a plain value in some events and as a nested object in others (
user="alice"vsuser={ "name": "alice" }). - Malformed date — a value that doesn’t match the mapped
dateformat, whenignore_malformedis not set. - Dynamic mapping guessed wrong — the first-ever value (e.g.
"12345") made Elasticsearch inferlong, and real values are strings.
How to diagnose
Read the reason — it names the field, its mapped type, and the value that failed:
grep 'mapper_parsing_exception' /var/log/logstash/logstash-plain.log | tail -5
Confirm the field’s current mapping in Elasticsearch:
curl -s 'http://es:9200/app-logs-2026.07.11/_mapping/field/response_time?pretty'
Reproduce the rejection in isolation to see exactly what Elasticsearch dislikes:
curl -s -XPOST 'http://es:9200/app-logs-2026.07.11/_doc?pretty' \
-H 'Content-Type: application/json' \
-d '{"response_time":"12.5ms"}'
If the DLQ is enabled, the rejected events (and their reasons) are captured for inspection:
ls -lh /var/lib/logstash/dead_letter_queue/main/
Fixes
1. Coerce the type in the Logstash filter so Elasticsearch always sees the mapped type. Strip units and convert, in the pipeline conf:
filter {
# "12.5ms" -> 12.5 (numeric)
mutate { gsub => ["response_time", "ms$", ""] }
mutate { convert => { "response_time" => "float" } }
# Normalize placeholders to a real null before a numeric field
if [bytes] in ["-", "N/A", "null", ""] {
mutate { remove_field => ["bytes"] }
} else {
mutate { convert => { "bytes" => "integer" } }
}
}
2. Fix the object-vs-scalar collision by renaming one shape so the two never share a field:
filter {
if [user] and [user][name] {
mutate { rename => { "[user][name]" => "user_name" } }
mutate { remove_field => ["user"] }
}
}
3. Make the mapping tolerant with an index template so a stray bad value is skipped instead of rejecting the whole document. Manage this in Elasticsearch (a composable template), not in Logstash:
PUT _index_template/app-logs
{
"index_patterns": ["app-logs-*"],
"template": {
"mappings": {
"properties": {
"response_time": { "type": "float", "ignore_malformed": true },
"status": { "type": "keyword" }
}
}
}
}
Note: mappings are immutable in place — changing an existing field’s type requires a rollover to a new index (the template applies to newly created indices), not an edit of the current one.
4. Capture rejects instead of dropping them by enabling the dead letter queue in logstash.yml, then reprocess after fixing the root cause:
dead_letter_queue.enable: true
path.dead_letter_queue: /var/lib/logstash/dead_letter_queue
dead_letter_queue.max_bytes: 1gb
What to watch out for
- The second type to arrive is what gets rejected — the field’s type is fixed by whichever document created it first, so “it worked yesterday” doesn’t mean the config is right.
ignore_malformedsilently drops the bad field’s value (the rest of the doc still indexes) — good for resilience, but you lose that datum, so alert on_ignored.- Enabling the DLQ without a pipeline that reads it just defers data loss until
dead_letter_queue.max_bytesevicts the oldest entries. - Fixing the template does nothing for the existing index — new data needs a rollover or a new data-stream backing index; historical conflicts need a reindex.
- Coerce at the source rather than raising limits or loosening mappings everywhere; a permissive
keyword-everything mapping hides real data-quality problems.
Related
- Logstash Error Guide: retrying failed action … 429
- Logstash Error Guide: dead letter queue is full
- Logstash Error Guide: version_conflict_engine_exception (409)
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.