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
Stuck on this Logstash error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
What this error means
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.
How the agent reports it
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.
Checking the agent configuration
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/
Agent configuration 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.
Step-by-step resolution
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
Safer agent defaults
- 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 agent errors
- Logstash Error Guide: retrying failed action … 429
- Logstash Error Guide: dead letter queue is full
- Logstash Error Guide: version_conflict_engine_exception (409)
Fixed it? Get 500 Logstash & 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.
Did this fix your issue?
Trending errors this week
The error guides other engineers are actually reading right now.
- 1mount: wrong fs type, bad option, bad superblock
- 2Docker 'failed to set up container networking': Fix the Bridge and IP Pool
- 3Docker 'failed to create shim task': How to Fix the containerd Runtime Error
- 4modprobe: FATAL: Module not found
- 5mount: wrong fs type, bad option, bad superblock
- 6Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
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.