Error log: This error appears when you try to update or delete a document that has been changed by another process.
JSON
{
"error" : {
"root_cause" : [
{
"type" : "version_conflict_engine_exception",
"reason" : "[index-name][doc-id]: version conflict, document already exists",
"index_uuid" : "...",
"shard" : "0",
"index" : "index-name"
}
],
"type" : "version_conflict_engine_exception",
"reason" : "[index-name][doc-id]: version conflict, document already exists",
"shard" : "0",
"index" : "index-name"
},
"status" : 409
}
Why… is this happening? OpenSearch uses optimistic concurrency control (also known as optimistic locking). Each document has a _version number. When you retrieve a document, you get its current version. If you then try to update or delete that document, and specify an if_seq_no and if_primary_term (or an older version parameter), OpenSearch checks if the document’s current version matches what you provided.
If the version numbers do not match, it means another process has modified the document since you last read it. To prevent overwriting someone else’s changes, OpenSearch throws a VersionConflictEngineException.
This is a good thing! It prevents data loss and inconsistent states in concurrent environments.
Common scenarios:
- Multiple writers: Two or more applications or threads try to update the same document simultaneously.
- Delayed updates: Your application reads a document, then some time passes, and another process updates it. When your application tries to update with the stale version, it fails.
- Accidental retries: A retry mechanism sends an old update request again.
Best practice:
- Understand concurrency: Design your applications to handle concurrent updates gracefully.
- Implement a retry strategy: For updates that are truly idempotent (can be safely retried), catch the
VersionConflictEngineExceptionand retry the operation. Before retrying, you’ll need to re-read the document to get its latest_seq_noand_primary_term(or_version) and apply your changes to that new version. - Use
op_type=createfor Initial Inserts: If you only want to create a document if it doesn’t already exist and prevent overwrites if it does, use theop_type=createparameter or the_createendpoint. This will throw an error if the document ID already exists. - Use
_updateAPI when possible: The_updateAPI is generally safer because it first fetches the document internally, applies your script or partial document, and then attempts the update, handling the versioning internally for you.
What else can I do? Designing robust concurrent update logic can be challenging. If you’re struggling with VersionConflictEngineException and need help structuring your application’s update strategy, the OpenSearch community can offer valuable insights. For more in-depth architectural guidance, reach out to the vibrant OpenSearch community for help and support on the OpenSearch Slack Channel.