SafeHandle cannot be null


Payments have a PaymentMethod (VISA, MasterCard, Cash, Cheque, Other etc). Users can manage the payment methods they accept. If a user chooses to delete a payment method, any payments made using that method are set to the the default payment method, Other.

A payment method looks like this

internal class PaymentMethod : RealmObject
    public string PaymentMethodId { get; set; }
    public string PaymentCode { get; set; }
    public string PaymentMethodName { get; set; }

    internal IQueryable<Payment> Payments { get; }

    public override string ToString() => PaymentCode;

and a payment looks like this

internal class Payment : RealmObject
    public string PaymentId { get; set; }
    public Order Order { get; set; }
    public PaymentMethod PaymentMethod { get; set; }
    public StaffMember StaffMember { get; set; }
    public DateTimeOffset PaymentDate { get; set; }
    public double PaymentAmount { get; set; }

I am trying to update payments that use payment methods that are to be removed like this.

foreach (PaymentMethod r in removes)
    IQueryable<Payment> updates = realm.All<Payment>().Where(e => e.PaymentMethod == r);
    foreach (Payment payment in updates)
        payment.PaymentMethod = defaultPaymentMethod;

The line foreach (Payment payment in updates) throws

SafeHandle cannot be null.

The full stack trace is

   at System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument, ExceptionResource resource)
   at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success)
   at Realms.QueryHandle.NativeMethods.query_object_equal(QueryHandle queryPtr, IntPtr columnIndex, ObjectHandle objectHandle, NativeException& ex)
   at Realms.RealmResultsVisitor.AddQueryEqual(QueryHandle queryHandle, String columnName, Object value, Type columnType)
   at Realms.RealmResultsVisitor.VisitBinary(BinaryExpression node)
   at Realms.RealmResultsVisitor.VisitMethodCall(MethodCallExpression node)
   at Realms.RealmResults`1.CreateHandle()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Lazy`1.CreateValue()
   at Realms.RealmCollectionBase`1.get_IsValid()


It appears there’s a corner case that isn’t gracefully handled in the our IQueryable implementation - we don’t check if the object you’re comparing to is managed. My guess is that r is not a managed RealmObject - do you first remove the payment methods or do you first set the payment’s payment method to default?


You are correct @nirinchev. removes were not managed. I’ve moved the creation of the list of removes to the same method and the issue went away.

but …

now, after successfully updating payments with the default payment method I delete the unwanted payment methods like this

IQueryable<PaymentMethod> removes = removes.AsQueryable();

and get

An exception of type ‘System.ArgumentException’ occurred in Realm.dll but was not handled in user code range should be the return value of .All or a LINQ query applied to it.


Yeah - you can’t convert a normal collection to a Realm collection (which is what the RemoveRange method expects). It’s designed to work with managed Realm queries, e.g.:

var query = realm.All<Foo>().Where(f => f.Bar > 5);

In your case you’ll just have to manually remove them one by one:

foreach (var remove in removes)

Hope this helps.


We now have error free update and deletion from a list. Thanks once again for your help @nirinchev.