Getting "document exists" error with collection.replace

I cannot figure out if I’m doing something wrong or it is a sdk issue, but I get a “document exists” error on the replace function. I mean, of course the document exists, that’s why I’m calling a replace function :sweat_smile:
Am I doing something wrong?

Node version 14.16.1
Couchbase sdk version 3.1.1
Couchbase version 6.6.2
Test code:

try {
    // creating the document...
    let id = 'test:1';
    let doc = { param: 'hi!' };
    let result = await collection.insert(id, doc);
    // updating the document...
    doc.param = 'hi!2';
    result = await collection.replace(id, doc, { cas: result.cas });
} catch(err) {
    console.error(err);
}

Error:

DocumentExistsError: document exists
    at _getWrappedErr (/testProject/node_modules/couchbase/lib/errors.js:864:14)
    at Object.wrapLcbErr (/testProject/node_modules/couchbase/lib/errors.js:1009:20)
    at /testProject/node_modules/couchbase/lib/collection.js:572:24 {
  cause: LibcouchbaseError { code: 305 },
  context: KeyValueErrorContext {
    status_code: 2,
    opaque: 3,
    cas: CbCas { '0': <Buffer 00 00 00 00 00 00 00 00> },
    key: 'test:1',
    bucket: 'my_bucket',
    collection: '',
    scope: '',
    context: '',
    ref: ''
  }
}

Going on with the experiments I discover that cas returned by the insert is wrong. It does not match the cas of the saved document:

let id = 'test:1';
let doc = { param: 'hi!' };
let result = await collection.insert(id, doc);
let savedDoc = await collection.get(id);
console.log(result.cas.toString());
console.log(savedDoc.cas.toString());

console:
1621434529246543872
1621434529256439808

Maybe that is the reason why I get the error. But, it should throws a “cas mismatch” error instead of “document exists”, shouldn’t it? So I think we have 2 bugs here:

  • CAS returned by insert is wrong
  • Wrong error throwed by replace

Hey @losapevo ,

The CAS values used by the SDK are specially wrapped objects and not represented as numbers. That being said, it does seem weird that using toString() is exhibiting this issue, since those CAS objects have custom toString() encoding to work around the potential loss of precision here. Can you confirm what happens if you log the CAS object itself without invoking toString()? It should print something like CbCas< 1621434529246543872 >.

Cheers, Brett

Yes, same behaviour. This is what I obtain running the same test code without invoking toString()

CbCas { '0': <Buffer 00 00 0e ca 11 83 80 16> }
CbCas { '0': <Buffer 00 00 28 ca 11 83 80 16> }

so I used the following code and it works like a charm.

var couchbase = require('couchbase')

var cluster = new couchbase.Cluster('couchbase://localhost', {
  username: 'Administrator',
  password: 'password',

}) 
const bucket = cluster.bucket("travel")
const collection = bucket.defaultCollection()


const createDoc = async (doc) => {
  try{
    let id = 'test:1';
      let doc = { param: 'hi!' };
      let result =  await collection.insert(id, doc);
  
      console.log(result)
      // updating the document...
      doc.param = 'hi!2';
      result =  await collection.replace(id, doc, { cas: result.cas });
  }catch(err){
    console.log(err)
  }
};

createDoc()

Also note I tried to change doc.param = 'hi!2'; to result.param = ‘hi!2’ and pass in the result as oppose to doc and that worked as well, I think you should pass in a result than doc.

Is it possible that syncgateway detects the new document, updates the metadata of the document and change the cas?

Hey @losapevo,

I wasn’t aware you were using Sync Gateway. That is exactly how Sync Gateway works, and would cause this behaviour.

Cheers, Brett

Ok, thank you @brett19, mistery solved! Even if I’m not happy with it. This means that every time I perform an insert/replace/upsert I need to call a get to obtain the right CAS (after SG modified it). The problem is that I can not distinguish if the cas obtained by the get is just the cas modified by SG (document body remains the same), or someone else did modify my doc…

What about the error I get, why a “document exists” instead of a “cas mismatch” error?

Hey @losapevo,

That indeed looks like a bug. The SDK should be translating that DocumentExists into a CasMismatch (protocol-level wise, both are the same status code). I’ll take a look into that.

Additionally, let me poke the sync gateway team and see if they have any insight here.

Cheers, Brett

1 Like

Just to confirm: yes, that’s the expected behaviour from the Sync Gateway side - when Sync Gateway imports a document to compute and store mobile metadata for that document, it’s going to update the cas value.