Bucket.ListSize error

I am getting an error of “Unable to cast object of type ‘System.String’ to type ‘System.Collections.Generic.List`1[System.Object]’” when attempting to get the size of a list using Bucket.ListSize(key) .
This happens after I insert a document into a list using Bucket.Insert to create the empty list and then Bucket.ListAppend to do the actual data insert. I can then see the document in the Couchbase web portal.

If the list is empty then the call does not have an error but as soon as a document is in the list there is the error. I am using the latest version of the api 2.7.15.

Also, I add to the list as described earlier with creating the list first because the ListAppend(key, object, true) is not working to create a list that does not exist. I have already submitted a ticket for that.

    public override bool ListAppend(string key, object value)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key), @"The key parameter must be string value with length greater than zero.");

        if (value == null)
            throw new ArgumentNullException(nameof(value), @"The value object parameter must not be null.");

        try
        {
            IResult result;

            if (Bucket.ListSize(key).Value == 0)
            {
                result = Bucket.Upsert(key, "[]");
                if (!result.Success) throw result.Exception;
            }

            result = Bucket.ListAppend(key, value, false);

            if (result.Success) return true;
            throw result.Exception;
        }
        catch (Exception ex)
        {
            //Logger.Error("[CouchbaseCacheProvider] Error while calling ListAdd", ex);
            return false;
        }
    }

Any help on this would be greatly appreciated.
James Wallace

I am also running into the same issue for adding a Map.

    public override bool DictionaryAdd(string key, string mapKey, object value)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key), @"The key parameter must be string value with length greater than zero.");

        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(mapKey), @"The mapKey parameter must be string value with length greater than zero.");

        if (value == null)
            throw new ArgumentNullException(nameof(value), @"The value object parameter must not be null.");

        try
        {
            IResult result;
            if (Bucket.MapSize(key).Value == 0)
            {
                result = Bucket.Upsert(key, "{}");
                if (!result.Success) throw new Exception();
            }

            result = Bucket.MapAdd(key, mapKey, JsonConvert.SerializeObject(value), false);

            if (result.Success) return true;
            throw result.Exception;
        }
        catch (Exception ex)
        {
            //Logger.Error("CouchbaseCacheProvider:MapAdd", ex);
            return false;
        }
    }

I am new to Couchbase and trying to learn it while I code for it in a project. Please let me know if you see anything that I am doing wrong with my code. Thanks again.

Hi @jrwallace96,

I just used your ListAppend code in a small console project like so:

static void Main(string[] args)
{
    var cluster = new Cluster(new ClientConfiguration
    {
        Servers = new List<Uri> { new Uri("http://localhost:8091") }
    });
    cluster.Authenticate("Administrator", "password");

    Bucket = cluster.OpenBucket("forumquestion");

    ListAppend("foo", new { bar="baz"});

    cluster.Dispose();
}

The only difference is that my ListAppend isn’t overriding anything. I’m not getting any errors or exceptions, so I must be missing something. Could you perhaps write a bare minimum console program to reproduce the conditions and the error you are getting?

Matthew,

Thank you for your response. Below is the code that you requested with comments to understand what I am seeing. I also have the console solution if you want that. I appreciate you looking at this and let me know if there are better ways of doing what I am attempting.

James

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Couchbase;
using Couchbase.Configuration.Client;
using Couchbase.Core;

namespace CouchbaseExampleWithError
{
    class Program
    {
        /// <summary>
        /// NOTES:
        /// I am running this on the latest community edition server as well as the latest version of the api
        /// Please step through this and read all of the notes to understand the issue I am seeing.
        /// </summary>
        private static IBucket Bucket;
        static void Main(string[] args)
        {
            var cluster = new Cluster(new ClientConfiguration
            {
                Servers = new List<Uri> { new Uri("http://localhost:8091") }
            });
            cluster.Authenticate("user", "password");

            Bucket = cluster.OpenBucket("BucketName");          

            //new list is created
            ListAppend("list1", new TestClass{Date = DateTime.Now, Id = 1, Name = "Jimmy"});
            //new list is created
            ListAppend("list2", new TestClass { Date = DateTime.Now, Id = 1, Name = "Beth" });
            //list is not added to because the ListSize function returns error
           ListAppend("list1", new TestClass { Date = DateTime.Now, Id = 1, Name = "Jimmy" });
            cluster.Dispose();
        }

        public static void ListAppend(string key, object value)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key),
                    @"The key parameter must be string value with length greater than zero.");

            if (value == null)
                throw new ArgumentNullException(nameof(value), @"The value object parameter must not be null.");

            try
            {
                IResult result;
                //when list does not exist it returns "key not found" and a value of zero, this seems correct and It allows me to 
go on and create the list using the Bucket.Upsert(key, "[]")  method
                //when list exists the ListSize method returns the error "Unable to cast object of type 'System.String' to type 
'System.Collections.Generic.List`1[System.Object]'" and does not give me a size
                //I find that if I use Bucket.Exists(key) this will work creating the list first with the "[]" characters and then doing 
with Bucket.ListAppend(key, value, false)
                //with the createList variable set to false and this will work
            

                var resultSize = Bucket.ListSize(key);
                if (resultSize.Value == 0)
                {
                    result = Bucket.Upsert(key, "[]");
                    if (!result.Success) throw result.Exception;
                }

                result = Bucket.ListAppend(key, value, false);

                //NOTE: I would prefer to use just Bucket.ListAppend(key, value, Bucket.ListSize(key) <= 0) but it does not work 
because of the ListSize issue and also 
                //even if it did work the command Bucket.ListAppend(key, value, true) with a bool true value being passed to the createList parameter it does not create a list.
                //Nor does it show an error in the result.  But, I will check the Couchbase Console web app and there is no list that exists.
                //I see an error in the console of "Error with retrieving document: list3" and "Object Not Found"  when I click the Retrieve Docs button

                result = Bucket.ListAppend("list3", value, true);
                var exists = Bucket.Exists("list3");

                if (!result.Success) throw result.Exception;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        private class TestClass
        {
            public int Id { get; set; }
            public DateTime Date { get; set; }
            public string Name { get; set; }
        }
    }
}

Okay @jrwallace96,

I think I have at least part of the picture. Your code is a workaround the fact that ListAppend(x,y,true) doesn’t appear to actually create a list document if it doesn’t exist? (Or at least that’s part of the problem?)

What I’ve found is that ListAppend does create a list document, but it creates it with a very short expiration. I don’t think this is expected behavior, but you can try this to see for yourself:

Bucket.ListAppend("mylist", new {foo = "bar"}, true, new TimeSpan(1,1,1,1));

If you create a list like that, you’ll see that it sticks around for a while. This is also (kinda) a workaround: you could give it a very distant future expiration.

I am going to confirm this with @jmorris and create a bug (unless I’m missing something).

Is this your primary issue, or is there something else?

My only other comment is that you are using ListSize, when you should probably use Exists instead (or at least check Success in the result instead of Value).

Update: After conferring with @jmorris, this does seem like a bug (also effects Queue and Map data structures, not just List). I’ve created a ticket here: https://issues.couchbase.com/browse/NCBC-2287

Matthew,

Thanks for the update. Yes, this is one of the issues that I am speaking of. The other issue was the exception “Unable to cast object of type ‘System.String’ to type 'System.Collections.Generic.List`1[System.Object]” upon trying to get the ListSize when creating the list without the timespan value. I assume that this message is because of the ListAppend issue. I am trying out the temporary fix that you sent me.