This error occurs when Elasticsearch encounters an unexpected or invalid key while parsing a query JSON object. The query structure doesn't conform to the Elasticsearch Query DSL syntax, typically due to incorrect nesting, misplaced query clauses, or malformed JSON.
The "ParsingException: Unknown key for a START_OBJECT" error indicates that Elasticsearch's query parser encountered a JSON object with a key it doesn't recognize at that position in the query structure. This is a parsing error that occurs during query validation, before the query is executed. Elasticsearch uses a strict JSON parser that expects queries to follow the Query DSL (Domain Specific Language) syntax. When it starts parsing an object (indicated by START_OBJECT, which is a '{' character), it expects specific keys based on the context. If it encounters a key that isn't valid in that position, it throws this parsing exception. Common scenarios that trigger this error: 1. Placing query clauses like "filter", "must", or "should" at the wrong nesting level 2. Using numeric or invalid keys where field names are expected 3. Incorrectly structuring bool queries or other compound queries 4. Query DSL syntax changes between Elasticsearch versions (especially 5.x and later) 5. Missing required wrapper objects around query clauses The error message typically includes the specific key that caused the problem, which helps identify where in your query the structure is incorrect.
Examine the full error message to find the problematic key and location:
# The error message typically looks like:
# "parsing_exception: Unknown key for a START_OBJECT in [filter]"
# "reason": "Unknown key for a START_OBJECT in [filter]",
# "line": 3,
# "col": 5
# Run the query with verbose error output
curl -X GET "localhost:9200/my-index/_search?error_trace=true" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": {}
},
"filter": {
"term": { "status": "active" }
}
}
'The error will point to the specific key (in this example, "filter") that is in the wrong position. Note the line and column numbers to locate the issue in your query.
The most common cause is placing "filter" at the root level. In Elasticsearch 5.x+, filters must be inside a bool query:
# INCORRECT - filter at root level
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": {}
},
"filter": {
"term": { "status": "active" }
}
}
'
# CORRECT - filter inside bool query
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": [
{ "match_all": {} }
],
"filter": [
{ "term": { "status": "active" } }
]
}
}
}
'
# Alternative: Use bool query with only filter (more efficient)
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"filter": [
{ "term": { "status": "active" } },
{ "range": { "created_at": { "gte": "2024-01-01" } } }
]
}
}
}
'Ensure must, should, filter, and must_not clauses are properly structured:
# INCORRECT - should clause not in array
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"should": {
"match": { "title": "error" }
}
}
}
}
'
# CORRECT - should clause in array
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"should": [
{ "match": { "title": "error" } },
{ "match": { "description": "exception" } }
],
"minimum_should_match": 1
}
}
}
'
# CORRECT - combining multiple bool clauses
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": [
{ "match": { "status": "published" } }
],
"should": [
{ "match": { "title": "elasticsearch" } },
{ "match": { "tags": "database" } }
],
"filter": [
{ "range": { "created_at": { "gte": "2024-01-01" } } }
],
"must_not": [
{ "term": { "archived": true } }
],
"minimum_should_match": 1
}
}
}
'Use JSON validators and Kibana Dev Tools to catch structural errors:
# Use jq to validate JSON syntax
echo '{
"query": {
"bool": {
"filter": [
{ "term": { "status": "active" } }
]
}
}
}' | jq .
# Use Python to validate and format
python3 << 'EOF'
import json
query = '''
{
"query": {
"bool": {
"filter": [
{ "term": { "status": "active" } }
]
}
}
}
'''
try:
parsed = json.loads(query)
print("Valid JSON:")
print(json.dumps(parsed, indent=2))
except json.JSONDecodeError as e:
print(f"JSON Error: {e}")
EOFUsing Kibana Dev Tools:
1. Open Kibana Dev Tools (Console)
2. Paste your query
3. Kibana will highlight syntax errors in red
4. Hover over errors for suggestions
5. Use auto-complete (Ctrl+Space) for valid query structures
Common JSON errors:
- Extra commas: { "field": "value", }
- Missing commas: { "a": 1 "b": 2 }
- Unbalanced brackets: { "query": { "match": {} }
- Invalid key names: numeric keys where field names expected
Replace numeric keys with proper field names or restructure the query:
# INCORRECT - using numeric keys in fields object
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": { "match_all": {} },
"_source": {
"0": "field1",
"1": "field2"
}
}
'
# CORRECT - use array for fields
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": { "match_all": {} },
"_source": ["field1", "field2"]
}
'
# INCORRECT - numeric keys in aggregations
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"aggs": {
"0": {
"terms": { "field": "category" }
}
}
}
'
# CORRECT - use descriptive aggregation names
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"aggs": {
"categories": {
"terms": {
"field": "category.keyword",
"size": 10
}
}
}
}
'If migrating from Elasticsearch 2.x to 5.x+, update deprecated syntax:
# Elasticsearch 2.x syntax (deprecated)
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"filtered": {
"query": { "match_all": {} },
"filter": { "term": { "status": "active" } }
}
}
}
'
# Elasticsearch 5.x+ syntax (current)
curl -X GET "localhost:9200/my-index/_search" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": { "term": { "status": "active" } }
}
}
}
'
# Update deprecated query types
# Old: "and", "or", "not" filters
# New: bool query with "must", "should", "must_not"
# Old syntax (Elasticsearch 2.x)
{
"query": {
"filtered": {
"filter": {
"and": [
{ "term": { "status": "active" } },
{ "range": { "price": { "gte": 10 } } }
]
}
}
}
}
# New syntax (Elasticsearch 5.x+)
{
"query": {
"bool": {
"filter": [
{ "term": { "status": "active" } },
{ "range": { "price": { "gte": 10 } } }
]
}
}
}## Advanced Query Debugging Techniques
### Using Elasticsearch Validate API
The Validate API helps identify query issues before execution:
# Validate query and get explanations
curl -X GET "localhost:9200/my-index/_validate/query?explain=true" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"filter": [
{ "term": { "status": "active" } }
]
}
}
}
'
# Response shows if query is valid and how it's interpreted
# {
# "valid": true,
# "explanations": [
# {
# "index": "my-index",
# "valid": true,
# "explanation": "status:active"
# }
# ]
# }### Query Rewrite for Understanding
Use the rewrite parameter to see how Elasticsearch processes your query:
curl -X GET "localhost:9200/my-index/_search?rewrite=true" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"filter": [
{ "prefix": { "title": "elastic" } }
]
}
}
}
'### Common Query DSL Patterns
Combining Multiple Conditions:
{
"query": {
"bool": {
"must": [
{ "match": { "title": "elasticsearch" } }
],
"should": [
{ "term": { "priority": "high" } },
{ "range": { "score": { "gte": 8 } } }
],
"filter": [
{ "term": { "status": "published" } },
{ "range": { "created_at": { "gte": "now-30d" } } }
],
"must_not": [
{ "term": { "archived": true } }
],
"minimum_should_match": 1,
"boost": 1.2
}
}
}Nested Queries:
{
"query": {
"nested": {
"path": "comments",
"query": {
"bool": {
"must": [
{ "match": { "comments.author": "john" } },
{ "range": { "comments.created_at": { "gte": "2024-01-01" } } }
]
}
}
}
}
}### Performance Considerations
Filter vs Must:
- Use filter for exact matches and ranges (not scored, cacheable)
- Use must for full-text search that needs scoring
- Filters are faster and use less memory due to caching
Query Optimization:
{
"query": {
"bool": {
"filter": [
{ "term": { "status": "active" } },
{ "range": { "timestamp": { "gte": "now-1d" } } }
],
"must": [
{ "match": { "description": "error" } }
]
}
},
"size": 10,
"_source": ["id", "title", "timestamp"],
"track_total_hits": false
}### Debugging with Explain API
See exactly why a document matches (or doesn't match):
# Explain why a specific document matches
curl -X GET "localhost:9200/my-index/_explain/document-id" -u "username:password" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": [
{ "match": { "title": "elasticsearch" } }
],
"filter": [
{ "term": { "status": "active" } }
]
}
}
}
'### Client Library Query Building
Using official clients helps avoid syntax errors:
# Python Elasticsearch client
from elasticsearch import Elasticsearch
es = Elasticsearch(["http://localhost:9200"])
# Query builder prevents structure errors
query = {
"bool": {
"must": [
{"match": {"title": "elasticsearch"}}
],
"filter": [
{"term": {"status": "active"}},
{"range": {"created_at": {"gte": "2024-01-01"}}}
]
}
}
response = es.search(index="my-index", query=query)// JavaScript Elasticsearch client
const { Client } = require('@elastic/elasticsearch');
const client = new Client({ node: 'http://localhost:9200' });
const response = await client.search({
index: 'my-index',
body: {
query: {
bool: {
must: [
{ match: { title: 'elasticsearch' } }
],
filter: [
{ term: { status: 'active' } },
{ range: { created_at: { gte: '2024-01-01' } } }
]
}
}
}
});### Version Migration Checklist
When upgrading Elasticsearch versions:
1. Review breaking changes in official migration guide
2. Test queries in development environment
3. Use Validate API to check all queries
4. Update deprecated query syntax before upgrade
5. Monitor parsing errors in logs after upgrade
6. Implement query version detection in application code
QueryShardException: No mapping found for [field] in order to sort on
How to fix "QueryShardException: No mapping found for field in order to sort on" in Elasticsearch
IndexNotFoundException: no such index [index_name]
How to fix "IndexNotFoundException: no such index [index_name]" in Elasticsearch
DocumentMissingException: [index][type][id]: document missing
DocumentMissingException: Document missing
AggregationExecutionException: Aggregation [agg_name] does not support sampling
How to fix "AggregationExecutionException: Aggregation [agg_name] does not support sampling" in Elasticsearch
ScriptException: compile error
ScriptException: compile error