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

  1. Re-query the collection to confirm the document still exists before updating
  2. Refresh the _id from a fresh query if the id may be stale
  3. Wrap the read-modify-write in a transaction (or use find-one-and-update) if the delete-vs-update race matters
  4. 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

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


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/75941eeb3fa91eb3. Report an issue: GitHub.