Resolving TargetException "Non-static method requires a target" in LINQ

I recently came across a situation in which a seemingly innocuous piece of LINQ threw a very opaque exception when used with Entity Framework 6.

The exception was this:

Call Stack: System.Reflection.TargetException: at System.Reflection.RuntimeMethodInfo.Invoke (System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e) at System.Reflection.RuntimePropertyInfo.GetValue (System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e) at

...

System.Linq.Enumerable.SingleOrDefault (System.Linq, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a) at MyProject.MyClass`1+d__3.MoveNext (MyProject, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null: /path/to/src/MyProject/MyClass.cs:67)

Message: Non-static method requires a target.

The real stack trace was 84 lines long, but I've cut it down to the relevant parts.

The line of code referenced at the end of the stack trace was the closing brace of a method. Cutting the method down to its basic parts, it went something like this:

private void MyMethod(int input)
{
    // more code here
    var obj = GetObj(input);
    var data = _context.Data.SingleOrDefault(d => d.Value = obj.Value);
    // more code here

} // this is the line referenced in the stack trace

It's more obvious with the rest of the method cut out, but the problem is the SingleOrDefault. You can see that in the penultimate line of the stack trace excerpt above, and happily my method only had one SingleOrDefault in it.

This error means that obj is null, so obj.Value can't be translated to SQL for executing against the database context. You might expect this to throw a NullReferenceException, but it doesn't. I won't pretend to know exactly why this is, but I assume it's to do with LINQ building up the query as an expression tree and only actually evaluating obj.Value later. If I had extracted obj.Value to the line above the LINQ, I would expect a NullReferenceException:

private void MyMethod(int input)
{
    // more code here
    var obj = GetObj(input);
    var val = obj.Value; // I believe this would throw a NullReferenceException
    var data = _context.Data.SingleOrDefault(d => d.Value = val);
    // more code here
}

Once you know what the TargetException means, the fix is straightforward. I did a null check on obj and everything was fine. In my case, obj was only null because of bad data creating an invalid situation, so I threw a custom exception:

private void MyMethod(int input)
{
    // more code here
    var obj = GetObj(input);

    if (obj is null)
    {
        throw new MyCustomException("Explanation of what is wrong with the data in this scenario and how to fix it.");
    }

    var data = _context.Data.SingleOrDefault(d => d.Value = obj.Value);
    // more code here
}