"cas must be a string" with replace() and remove()


I have an issue using CAS with replace() and remove(): it doesn’t accept the CAS value I get returned from a query.

$query = N1qlQuery::fromString('SELECT META(`test`) `meta`, * FROM `test`);

$result = $bucket->query($query);

$id = $result->rows[0]->meta->id;
$cas = $result->rows[0]->meta->cas;
$value = $result->rows[0]->test;

$bucket->replace($id, $value, ['cas' => $cas]);
$bucket->remove($id, ['cas' => $cas]);

This results for both the replace() and remove() in a Couchbase exception:

Couchbase\Exception: cas must be a string

The result from the query is as follows:

    "rows": [
            "meta": {
                "cas": 1562856092781510656,
                "expiration": 0,
                "flags": 33554438,
                "id": "...",
                "type": "json"
            "test": {
    "requestId": "cf4bbe17-44b0-42da-bc29-108f9dc4e123",
    "status": "success",
    "signature": {
        "*": "*",
        "meta": "object"
    "metrics": {
        "elapsedTime": "1.783554ms",
        "executionTime": "1.704191ms",
        "resultCount": 1,
        "resultSize": 1268

And if I typecast the CAS to a string I get another Couchbase exception:

Couchbase\Exception: LCB_KEY_EEXISTS: The key already exists in the server. If you have supplied a CAS then the key exists with a CAS value different than specified

I’m using version the following Couchbase versions in PHP 7.0 in Ubuntu 18.04:

$ pecl info couchbase | grep Version
Release Version       2.6.1 (stable)
API Version           2.3.0 (stable)

$ php -i | grep libcouchbase
libcouchbase runtime version => 2.10.3 (git: b387722192f0bc49b0a846859610493e2f8129cd)
libcouchbase headers version => 2.10.3 (git: b387722192f0bc49b0a846859610493e2f8129cd)

What am I doing wrong?


CAS value in PHP SDK 2 could be represented 36-base encoded 64-bit unsigned integer:

The problem is that the value in JSON could be truncated or imprecise because of JSON generator/parser, so you have to use

select tostring(meta(default).cas) as cas from default limit 1

And then turn that string into another 36-base encoded string (but pay attention, that in PHP size of the int is platform-dependent, and they are always signed)

Converting the CAS to base 36 indeed did the trick:

$cas = base_convert((string) $cas, 10, 36);

Thank you very much for the fast reply!