How to fix DocumentMissingException: [index][type][id]: document missing in Elasticsearch
This error occurs when attempting to update, delete, or retrieve a document that does not exist in the Elasticsearch index. It commonly happens during concurrent operations or when update requests target non-existent documents.
Quick fix
Fixes DocumentMissingException: [index][type][id]: document missing
# Check if document exists
curl -X GET "localhost:9200/my_index/_doc/doc_id?pretty"- Verify the document exists before updating
- Use upsert to insert if document does not exist
- Use doc_as_upsert for simpler upsert operations
- Handle the exception gracefully in application code
# Check if document existscurl -X GET "localhost:9200/my_index/_doc/doc_id?pretty"DocumentMissingException: [index][type][id]: document missing
What this error means
The DocumentMissingException is thrown by Elasticsearch when an operation requires an existing document but cannot find it in the specified index. Unlike index operations that create or overwrite documents, update and delete operations expect the document to already exist at the given ID. This exception is Elasticsearch's way of signaling that your application attempted to modify or access a document that either never existed, was already deleted, or was removed between the time you checked for its existence and when you tried to operate on it. The error includes the index name, type (deprecated in newer versions), and document ID to help identify which document caused the issue. Understanding this error is crucial for building resilient Elasticsearch applications, as it often indicates race conditions, stale references, or logic errors in document lifecycle management.
Typical symptoms
- Update API requests fail with 404 status code
- Bulk update operations report document_missing_exception errors for specific documents
- Delete operations fail even though the document was recently retrieved
- Application logs show "[index][type][id]: document missing" errors
- Upsert operations unexpectedly throw exceptions despite doc_as_upsert being enabled
- Retry logic for failed updates continues to fail with the same error
- GET requests return the document but subsequent UPDATE fails immediately
Common causes
- Attempting to update a document that has never been indexed
- Document was deleted by another process between existence check and update operation
- Using wrong document ID or index name in the update request
- Concurrent delete and update operations targeting the same document
- Stale document references in application cache or state
- Document was deleted as part of index maintenance or TTL policy
- Race condition in distributed systems where multiple services operate on the same document
- Retry of an update request after the document was deleted during a version conflict
- Bulk operations where some documents exist and others do not
- Document deleted by background cleanup jobs or automated scripts
How to fix "DocumentMissingException: [index][type][id]: document missing"
Use a GET request to check if the document exists before attempting to update it:
# Check if document exists
curl -X GET "localhost:9200/my_index/_doc/doc_id?pretty"Or in your application code:
const { body: exists } = await client.exists({
index: 'my_index',
id: 'doc_id'
});
if (exists) {
// Proceed with update
await client.update({
index: 'my_index',
id: 'doc_id',
body: {
doc: { field: 'value' }
}
});
}This prevents attempting updates on non-existent documents.
Add an upsert clause to your update request to create the document if it doesn't exist:
curl -X POST "localhost:9200/my_index/_update/doc_id?pretty" \
-H 'Content-Type: application/json' -d'
{
"doc": {
"field": "updated_value",
"counter": 1
},
"upsert": {
"field": "initial_value",
"counter": 1,
"created_at": "2024-01-01T00:00:00Z"
}
}
'In JavaScript/Node.js:
await client.update({
index: 'my_index',
id: 'doc_id',
body: {
doc: {
field: 'updated_value',
counter: 1
},
upsert: {
field: 'initial_value',
counter: 1,
created_at: new Date().toISOString()
}
}
});The upsert field defines what to insert if the document doesn't exist.
Set doc_as_upsert to true to use the doc content as both update and insert:
curl -X POST "localhost:9200/my_index/_update/doc_id?pretty" \
-H 'Content-Type: application/json' -d'
{
"doc": {
"field": "value",
"counter": 1
},
"doc_as_upsert": true
}
'In Python:
from elasticsearch import Elasticsearch
es = Elasticsearch(['localhost:9200'])
es.update(
index='my_index',
id='doc_id',
body={
'doc': {
'field': 'value',
'counter': 1
},
'doc_as_upsert': True
}
)Note: There are known edge cases where doc_as_upsert can still throw DocumentMissingException in high-concurrency scenarios.
Wrap update operations in try-catch blocks to handle missing documents:
try {
await client.update({
index: 'my_index',
id: 'doc_id',
body: {
doc: { field: 'value' }
}
});
} catch (error) {
if (error.meta?.statusCode === 404) {
console.log('Document not found, creating new document');
await client.index({
index: 'my_index',
id: 'doc_id',
body: { field: 'value' }
});
} else {
throw error;
}
}In Java:
try {
UpdateRequest request = new UpdateRequest("my_index", "doc_id")
.doc("field", "value");
client.update(request, RequestOptions.DEFAULT);
} catch (ElasticsearchException e) {
if (e.status() == RestStatus.NOT_FOUND) {
IndexRequest indexRequest = new IndexRequest("my_index")
.id("doc_id")
.source("field", "value");
client.index(indexRequest, RequestOptions.DEFAULT);
} else {
throw e;
}
}If you want to overwrite the entire document regardless of existence, use the index API:
curl -X PUT "localhost:9200/my_index/_doc/doc_id?pretty" \
-H 'Content-Type: application/json' -d'
{
"field": "value",
"counter": 1,
"updated_at": "2024-01-01T00:00:00Z"
}
'In application code:
await client.index({
index: 'my_index',
id: 'doc_id',
body: {
field: 'value',
counter: 1,
updated_at: new Date().toISOString()
}
});Index operations create the document if it doesn't exist or replace it if it does, never throwing DocumentMissingException.
Configure retry logic to handle version conflicts that might precede document deletion:
curl -X POST "localhost:9200/my_index/_update/doc_id?retry_on_conflict=3&pretty" \
-H 'Content-Type: application/json' -d'
{
"doc": {
"field": "value"
},
"doc_as_upsert": true
}
'In client code:
await client.update({
index: 'my_index',
id: 'doc_id',
retry_on_conflict: 3,
body: {
doc: { field: 'value' },
doc_as_upsert: true
}
});This helps handle concurrent updates but won't prevent DocumentMissingException if the document is truly gone.
When using bulk operations, check individual item responses for errors:
const { body: bulkResponse } = await client.bulk({
refresh: true,
body: [
{ update: { _index: 'my_index', _id: 'doc1' } },
{ doc: { field: 'value1' }, doc_as_upsert: true },
{ update: { _index: 'my_index', _id: 'doc2' } },
{ doc: { field: 'value2' }, doc_as_upsert: true },
]
});
if (bulkResponse.errors) {
const erroredDocuments = [];
bulkResponse.items.forEach((action, i) => {
const operation = Object.keys(action)[0];
if (action[operation].error) {
erroredDocuments.push({
status: action[operation].status,
error: action[operation].error,
operation: body[i * 2],
document: body[i * 2 + 1]
});
}
});
console.log('Failed documents:', erroredDocuments);
}This allows you to handle missing documents individually without failing the entire bulk operation.
Advanced notes
Race Conditions and Eventual Consistency
DocumentMissingException is often a symptom of race conditions in distributed systems. If you have multiple services or processes operating on the same documents, consider implementing optimistic locking using the _seq_no and _primary_term fields:
// Get document with sequence number
const { body: doc } = await client.get({
index: 'my_index',
id: 'doc_id'
});
// Update with optimistic locking
await client.update({
index: 'my_index',
id: 'doc_id',
if_seq_no: doc._seq_no,
if_primary_term: doc._primary_term,
body: {
doc: { field: 'new_value' }
}
});This ensures the document hasn't changed between read and write operations.
Known Issues with doc_as_upsert
There are documented cases where doc_as_upsert can still produce DocumentMissingException in high-concurrency scenarios, particularly during retries after version conflicts. This appears to be related to timing issues in Elasticsearch's internal retry mechanism. If you encounter this, consider using explicit upsert fields instead of doc_as_upsert, or implement application-level retry logic with exponential backoff.
Scripted Updates and Missing Documents
When using scripted updates, you can detect missing documents within the script using ctx._source:
curl -X POST "localhost:9200/my_index/_update/doc_id?pretty" \
-H 'Content-Type: application/json' -d'
{
"script": {
"source": "ctx._source.counter += params.count",
"params": {
"count": 1
}
},
"upsert": {
"counter": 1
}
}
'The script runs only if the document exists; otherwise, the upsert document is inserted.
Index Refresh and Visibility
If you're experiencing DocumentMissingException immediately after creating a document, the issue might be index refresh timing. By default, Elasticsearch refreshes indexes every second. For immediate visibility:
// Index with immediate refresh
await client.index({
index: 'my_index',
id: 'doc_id',
refresh: true, // or 'wait_for'
body: { field: 'value' }
});However, using refresh on every operation impacts performance and should be used sparingly.
Monitoring Document Lifecycle
For production systems experiencing frequent DocumentMissingExceptions, implement audit logging to track document creation, updates, and deletions:
const auditLog = {
timestamp: new Date().toISOString(),
operation: 'update',
index: 'my_index',
doc_id: 'doc_id',
success: false,
error: 'document_missing_exception'
};
await logAuditEvent(auditLog);This helps identify patterns like which documents are frequently missing and whether the issue is systematic or isolated.
Frequently asked questions
- What does "DocumentMissingException: [index][type][id]: document missing" mean?
- The DocumentMissingException is thrown by Elasticsearch when an operation requires an existing document but cannot find it in the specified index. Unlike index operations that create or overwrite documents, update and delete operations expect the document to already exist at the given ID. This exception is Elasticsearch's way of signaling that your application attempted to modify or access a document that either never existed, was already deleted, or was removed between the time you checked for its existence and when you tried to operate on it.
- How do I fix "DocumentMissingException: [index][type][id]: document missing"?
- This error occurs when attempting to update, delete, or retrieve a document that does not exist in the Elasticsearch index. It commonly happens during concurrent operations or when update requests target non-existent documents.
- What causes "DocumentMissingException: [index][type][id]: document missing"?
- Attempting to update a document that has never been indexed Document was deleted by another process between existence check and update operation Using wrong document ID or index name in the update request
- Is the "DocumentMissingException: [index][type][id]: document missing" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚Elasticsearch Official Documentation
- 📖discuss.elastic.co - 325777(Official Docs)
- 🐙github.com - 1262(GitHub)
- 📖discuss.elastic.co - 82438(Official Docs)
- 📖elastic.co - operation update(Official Docs)
- 📖discuss.elastic.co - 370735(Official Docs)
- 🐙github.com - 6355(GitHub)
- 🔗
- 📖discuss.elastic.co - 42921(Official Docs)