From 4ff43740ba56e610182d5ead7ee1407604a3634b Mon Sep 17 00:00:00 2001 From: "slav.babanin" Date: Mon, 2 Feb 2026 23:43:24 -0800 Subject: [PATCH 1/3] Add RetryableWriteError to write concern error in bulk writes. JAVA-6087 --- .../operation/CommandOperationHelper.java | 9 +++++--- .../operation/MixedBulkWriteOperation.java | 23 +++++++++++++------ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java b/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java index 8332ad916fb..4bd56d1d025 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java +++ b/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java @@ -237,10 +237,13 @@ private static boolean decideRetryableAndAddRetryableWriteErrorLabel(final Throw return exception.hasErrorLabel(RETRYABLE_WRITE_ERROR_LABEL); } + static boolean shouldAddRetryableWriteErrorLabel(final MongoException exception, final int maxWireVersion) { + return (maxWireVersion >= 9 && exception instanceof MongoSocketException) + || (maxWireVersion < 9 && isRetryableException(exception)); + } + static void addRetryableWriteErrorLabel(final MongoException exception, final int maxWireVersion) { - if (maxWireVersion >= 9 && exception instanceof MongoSocketException) { - exception.addLabel(RETRYABLE_WRITE_ERROR_LABEL); - } else if (maxWireVersion < 9 && isRetryableException(exception)) { + if (shouldAddRetryableWriteErrorLabel(exception, maxWireVersion)) { exception.addLabel(RETRYABLE_WRITE_ERROR_LABEL); } } diff --git a/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java b/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java index 43cf4b4cf6c..2173f09a9b5 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java @@ -61,10 +61,12 @@ import static com.mongodb.internal.async.ErrorHandlingResultCallback.errorHandlingCallback; import static com.mongodb.internal.operation.AsyncOperationHelper.exceptionTransformingCallback; import static com.mongodb.internal.operation.AsyncOperationHelper.withAsyncSourceAndConnection; +import static com.mongodb.internal.operation.CommandOperationHelper.RETRYABLE_WRITE_ERROR_LABEL; import static com.mongodb.internal.operation.CommandOperationHelper.addRetryableWriteErrorLabel; import static com.mongodb.internal.operation.CommandOperationHelper.logRetryExecute; import static com.mongodb.internal.operation.CommandOperationHelper.loggingShouldAttemptToRetryWriteAndAddRetryableLabel; import static com.mongodb.internal.operation.CommandOperationHelper.onRetryableWriteAttemptFailure; +import static com.mongodb.internal.operation.CommandOperationHelper.shouldAddRetryableWriteErrorLabel; import static com.mongodb.internal.operation.CommandOperationHelper.transformWriteException; import static com.mongodb.internal.operation.CommandOperationHelper.validateAndGetEffectiveWriteConcern; import static com.mongodb.internal.operation.OperationHelper.LOGGER; @@ -287,8 +289,11 @@ private BulkWriteResult executeBulkWriteBatch( connection.getDescription().getServerAddress(), "errMsg", timeoutContext); if (writeConcernBasedError != null) { if (currentBulkWriteTracker.lastAttempt()) { - addRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion); - addErrorLabelsToWriteConcern(result.getDocument("writeConcernError"), writeConcernBasedError.getErrorLabels()); + // The raw result is not exposed to the user, so labels can be added directly here. + // They are further processed as if they originated from the server. + if (shouldAddRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion)) { + addRetryableErrorLabelToResult(result); + } } else if (loggingShouldAttemptToRetryWriteAndAddRetryableLabel(retryState, writeConcernBasedError)) { throw new MongoWriteConcernWithResponseException(writeConcernBasedError, result); } @@ -341,9 +346,11 @@ private void executeBulkWriteBatchAsync( connection.getDescription().getServerAddress(), "errMsg", operationContext.getTimeoutContext()); if (writeConcernBasedError != null) { if (currentBulkWriteTracker.lastAttempt()) { - addRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion); - addErrorLabelsToWriteConcern(result.getDocument("writeConcernError"), - writeConcernBasedError.getErrorLabels()); + // The raw result is not exposed to the user, so labels can be added directly here. + // They are further processed as if they originated from the server. + if (shouldAddRetryableWriteErrorLabel(writeConcernBasedError, maxWireVersion)) { + addRetryableErrorLabelToResult(result); + } } else if (loggingShouldAttemptToRetryWriteAndAddRetryableLabel(retryState, writeConcernBasedError)) { iterationCallback.onResult(null, new MongoWriteConcernWithResponseException(writeConcernBasedError, result)); @@ -456,9 +463,11 @@ private boolean shouldExpectResponse(final BulkWriteBatch batch, final WriteConc return effectiveWriteConcern.isAcknowledged() || (ordered && batch.hasAnotherBatch()); } - private void addErrorLabelsToWriteConcern(final BsonDocument result, final Set errorLabels) { + private void addRetryableErrorLabelToResult(final BsonDocument result) { if (!result.containsKey("errorLabels")) { - result.put("errorLabels", new BsonArray(errorLabels.stream().map(BsonString::new).collect(Collectors.toList()))); + BsonArray labelsArray = new BsonArray(); + labelsArray.add(new BsonString(RETRYABLE_WRITE_ERROR_LABEL)); + result.put("errorLabels", labelsArray); } } From 4b97a8f4bf568528585665a4b159e7a5b39cc343 Mon Sep 17 00:00:00 2001 From: "slav.babanin" Date: Tue, 3 Feb 2026 18:34:50 -0800 Subject: [PATCH 2/3] Remove unused imports. JAVA-6087 --- .../mongodb/internal/operation/MixedBulkWriteOperation.java | 2 -- .../com/mongodb/client/unified/UnifiedTestModifications.java | 4 ---- 2 files changed, 6 deletions(-) diff --git a/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java b/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java index 2173f09a9b5..e24bb6eb906 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/MixedBulkWriteOperation.java @@ -51,9 +51,7 @@ import java.util.List; import java.util.Locale; import java.util.Optional; -import java.util.Set; import java.util.function.Supplier; -import java.util.stream.Collectors; import static com.mongodb.assertions.Assertions.assertTrue; import static com.mongodb.assertions.Assertions.isTrueArgument; diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java index 2225f837ec5..91e98c0ab31 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java @@ -400,10 +400,6 @@ public static void applyCustomizations(final TestDef def) { .test("retryable-writes", "retryable-writes insertOne serverErrors", "InsertOne succeeds after retryable writeConcernError") .test("retryable-writes", "retryable-writes bulkWrite serverErrors", "BulkWrite succeeds after retryable writeConcernError in first batch"); - def.skipJira("https://jira.mongodb.org/browse/JAVA-5341") - .when(() -> isDiscoverableReplicaSet() && serverVersionLessThan(4, 4)) - .test("retryable-writes", "retryable-writes insertOne serverErrors", - "RetryableWriteError label is added based on writeConcernError in pre-4.4 mongod response"); // server-discovery-and-monitoring (SDAM) From 9099b0f06d879c5503fd009fad906b2d61af1288 Mon Sep 17 00:00:00 2001 From: "slav.babanin" Date: Tue, 3 Feb 2026 18:51:50 -0800 Subject: [PATCH 3/3] Remove unused import. --- .../com/mongodb/client/unified/UnifiedTestModifications.java | 1 - 1 file changed, 1 deletion(-) diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java index 91e98c0ab31..345a90908b8 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java @@ -25,7 +25,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet; import static com.mongodb.ClusterFixture.isSharded; import static com.mongodb.ClusterFixture.serverVersionLessThan; import static com.mongodb.assertions.Assertions.assertNotNull;