{"record":{"id":"75941eeb3fa91eb3","repo":"t8y2/dbx","slug":"no-document-matched-id-id-it-may-have-been-del","errorCode":null,"errorMessage":"No document matched _id <id>. It may have been deleted or its _id changed since the query ran.","messagePattern":"No document matched _id <id>\\. It may have been deleted or its _id changed since the query ran\\.","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java","lineNumber":1562,"sourceCode":"        MongoClient c = requireClient();\n        String database = params.get(\"database\").getAsString();\n        String collection = params.get(\"collection\").getAsString();\n        String id = params.get(\"id\").getAsString();\n        String docJson = params.get(\"doc_json\").getAsString();\n\n        var col = c.getDatabase(database).getCollection(collection);\n        Document newDoc = documentForWrite(docJson);\n        var filter = new Document(\"_id\", parseId(id));\n        var result = isUpdateOperatorDocument(newDoc)\n            ? col.updateOne(filter, newDoc)\n            : col.replaceOne(filter, replacementDocument(newDoc));\n        requireMatchedDocument(id, result);\n        return Collections.singletonMap(\"modified_count\", result.getModifiedCount());\n    }\n\n    static void requireMatchedDocument(String id, UpdateResult result) {\n        if (result.getMatchedCount() == 0) {\n            throw new IllegalStateException(noMatchingDocumentError(id));\n        }\n    }\n\n    private static String noMatchingDocumentError(String id) {\n        String display = decodeStringDocumentId(id);\n        return \"No document matched _id \" + (display == null ? id : display)\n            + \". It may have been deleted or its _id changed since the query ran.\";\n    }\n\n    private static Object updateDocuments(JsonObject params) {\n        MongoClient c = requireClient();\n        String database = params.get(\"database\").getAsString();\n        String collection = params.get(\"collection\").getAsString();\n        String filterJson = params.get(\"filter_json\").getAsString();\n        String updateJson = params.get(\"update_json\").getAsString();\n        boolean many = params.get(\"many\").getAsBoolean();\n        String optionsJson = params.has(\"options_json\") && !params.get(\"options_json\").isJsonNull()\n            ? params.get(\"options_json\").getAsString()","sourceCodeStart":1544,"sourceCodeEnd":1580,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java#L1544-L1580","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nUpdateResult r = collection.updateOne(eq(\"_id\", id), updates);\n// may silently match nothing / later throw here\n// after\nUpdateResult r = collection.updateOne(eq(\"_id\", id), updates);\nif (r.getMatchedCount() == 0) {\n    // re-fetch or create, or surface a 404-style response\n    refreshStaleDocument(id);\n}","handlingStrategy":"try-catch","validationCode":"const stillExists = await queryOneById(id);\nif (!stillExists) {\n  return handleStaleRow(id); // refresh UI, surface 404, or recreate\n}","typeGuard":null,"tryCatchPattern":"try {\n  agent.updateById(id, updates);\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"No document matched _id\")) {\n    // document was deleted or _id changed since it was queried\n    await refreshFromSource(id); // re-query, retry with fresh _id, or surface not-found\n  } else throw e;\n}","preventionTips":["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"],"tags":["mongodb","stale-document","concurrency","update"],"backgroundTag":"document-not-found","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}