Bug with Subdoc Mutate in 3.0.1


There is a bug with subdoc mutate requests in the latest java sdk (3.0.1) when using both document flags and an expiration, e.g.:

collection.mutateIn(keyname, Arrays.asList(
                            upsert("a", "b"),
                            upsert("c", "d"),
mutateInOptions().storeSemantics(StoreSemantics.UPSERT).expiry(Duration.ofSeconds(60 * 60 * 24)));

This generates the following packet:

As seen the expiration is being read as part of the flags (0x01) and therefore the wrong value. This command then gives an error, presumably for an incorrect expiration value (More than 30 days but has passed).

The flags and the expiration are the wrong order here: https://github.com/couchbase/couchbase-jvm-clients/blob/master/core-io/src/main/java/com/couchbase/client/core/msg/kv/SubdocMutateRequest.java#L117-L123

The old sdk writes them in the correct order (expiration first): https://github.com/couchbase/couchbase-jvm-core/blob/63ede7f5811c818c7519200761bf4eae02b8b437/src/main/java/com/couchbase/client/core/endpoint/kv/KeyValueHandler.java#L883-L907


1 Like

@william thanks for reporting! We’ll take a look soon :slight_smile:

Yes, thank you for the detailed investigation @william. I’ve logged https://issues.couchbase.com/browse/JCBC-1600 for this.
For now, the workaround is to do a set-and-replace on the document - e.g. full document rather than Sub-Document.

Thanks. I’ve just rebuilt the jar myself with the fix and that is working ok.


diff --git a/core-io/src/main/java/com/couchbase/client/core/msg/kv/SubdocMutateRequest.java b/core-io/src/main/java/com/couchbase/client/core/msg/kv/SubdocMutateRequest.java
index 3615bbd..b3f057c 100644
--- a/core-io/src/main/java/com/couchbase/client/core/msg/kv/SubdocMutateRequest.java
+++ b/core-io/src/main/java/com/couchbase/client/core/msg/kv/SubdocMutateRequest.java
@@ -115,12 +115,12 @@ public class SubdocMutateRequest extends BaseKeyValueRequest<SubdocMutateRespons
       key = encodedKeyWithCollection(alloc, ctx);
       extras = alloc.buffer();
-      if (flags != 0) {
-        extras.writeByte(flags);
-      }
       if (expiration != 0) {
         extras.writeInt((int) expiration);
+      if (flags != 0) {
+        extras.writeByte(flags);
+      }

Yes, that’s the fix. I’ve got it checked in today so it should make the next java-client release. Thanks again for reporting this!