t8y2/dbx · error · java.lang.IllegalStateException
No document matched _id <id>. It may have been deleted or it
Error message
No document matched _id <id>. It may have been deleted or its _id changed since the query ran.
What it means
requireMatchedDocument inspects the UpdateResult after an update by _id; if the matched count is zero, no document with that _id existed when the update ran. The message decodes the internal id for display when possible. This is a staleness/concurrency signal: the row the caller saw in a previous query is gone or its _id changed.
Source
Thrown at agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java:1562
MongoClient c = requireClient();
String database = params.get("database").getAsString();
String collection = params.get("collection").getAsString();
String id = params.get("id").getAsString();
String docJson = params.get("doc_json").getAsString();
var col = c.getDatabase(database).getCollection(collection);
Document newDoc = documentForWrite(docJson);
var filter = new Document("_id", parseId(id));
var result = isUpdateOperatorDocument(newDoc)
? col.updateOne(filter, newDoc)
: col.replaceOne(filter, replacementDocument(newDoc));
requireMatchedDocument(id, result);
return Collections.singletonMap("modified_count", result.getModifiedCount());
}
static void requireMatchedDocument(String id, UpdateResult result) {
if (result.getMatchedCount() == 0) {
throw new IllegalStateException(noMatchingDocumentError(id));
}
}
private static String noMatchingDocumentError(String id) {
String display = decodeStringDocumentId(id);
return "No document matched _id " + (display == null ? id : display)
+ ". It may have been deleted or its _id changed since the query ran.";
}
private static Object updateDocuments(JsonObject params) {
MongoClient c = requireClient();
String database = params.get("database").getAsString();
String collection = params.get("collection").getAsString();
String filterJson = params.get("filter_json").getAsString();
String updateJson = params.get("update_json").getAsString();
boolean many = params.get("many").getAsBoolean();
String optionsJson = params.has("options_json") && !params.get("options_json").isJsonNull()
? params.get("options_json").getAsString()View on GitHub (pinned to c0390bff16)
Solutions
- Re-query the collection to confirm the document still exists before updating
- Refresh the _id from a fresh query if the id may be stale
- Wrap the read-modify-write in a transaction (or use find-one-and-update) if the delete-vs-update race matters
- Handle the missing-document case gracefully in the UI/API instead of treating it as a hard failure
Example fix
// before
UpdateResult r = collection.updateOne(eq("_id", id), updates);
// may silently match nothing / later throw here
// after
UpdateResult r = collection.updateOne(eq("_id", id), updates);
if (r.getMatchedCount() == 0) {
// re-fetch or create, or surface a 404-style response
refreshStaleDocument(id);
} Defensive patterns
Strategy: try-catch
Validate before calling
const stillExists = await queryOneById(id);
if (!stillExists) {
return handleStaleRow(id); // refresh UI, surface 404, or recreate
} Try / catch
try {
agent.updateById(id, updates);
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("No document matched _id")) {
// document was deleted or _id changed since it was queried
await refreshFromSource(id); // re-query, retry with fresh _id, or surface not-found
} else throw e;
} Prevention
- Re-fetch the document immediately before updating in read-modify-write flows
- Use transactions or find-one-and-update to avoid delete/update races
- Never cache _id values across long-lived UI sessions without revalidation
- After bulk re-imports, treat previously stored _ids as stale
When it happens
Trigger: Calling update/delete-by-id style operations where the _id string no longer matches any document: the document was deleted between query and update; the _id was modified by another writer; the id string is stale from a cached result; or the raw/encoded _id form was passed after re-import of data with new ids.
Common situations: Read-modify-write flows without transactions where another client deleted the document; retries replaying an update after a delete; UIs holding stale rows in long-lived forms; data re-seeded between query and update in dev/test environments.
Related errors
- arrayFilters must be an array
- Each arrayFilters entry must be an object
- JDBC Session was quarantined while waiting for a connection
- Interrupted while waiting for a JDBC workload lease
- Interrupted while waiting for the JDBC physical connection b
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/75941eeb3fa91eb3.
Report an issue: GitHub.