System.ArrayTypeMismatchException

The exception that is thrown when an attempt is made to store an element of the wrong type within an array.

Minimum version: >= 1.1 >= Core 1.0

Statistics

27
elmah.io logo 25

How to handle it

try
{

}
catch (System.ArrayTypeMismatchException e)
{

}
try
{

}
catch (System.ArrayTypeMismatchException e) when (e.Message.Contains("something"))
{

}
try
{

}
catch (System.ArrayTypeMismatchException e) when (LogException(e))
{

}

private static bool LogException(Exception e)
{
    logger.LogError(...);
    return false;
}

How to avoid it

We haven't written anything about avoiding this exception yet. Got a good tip on how to avoid throwing System.ArrayTypeMismatchException? Feel free to reach out through the support widget in the lower right corner with your suggestions.

Links

YouTube videos

Possible fixes from StackOverflow

Okay, this really depends on a few oddities combined:

  • Even though in C# you can't cast a byte[] to an sbyte[] directly, the CLR allows it:

    var foo = new byte[] {246, 127};
    // This produces a warning at compile-time, and the C# compiler "optimizes"
    // to the constant "false"
    Console.WriteLine(foo is sbyte[]);
    
    object x = foo;
    // Using object fools the C# compiler into really consulting the CLR... which
    // allows the conversion, so this prints True
    Console.WriteLine(x is sbyte[]);
    
  • Cast<T>() optimizes such that if it thinks it doesn't need to do anything (via an is check like the above) it returns the original reference - so that's happening here.

  • ToList() delegates to the constructor of List<T> taking an IEnumerable<T>

  • That constructor is optimized for ICollection<T> to use CopyTo... and that's what's failing. Here's a version which has no method calls other than CopyTo:

    object bytes = new byte[] { 246, 127 };
    
    // This succeeds...
    ICollection<sbyte> list = (ICollection<sbyte>) bytes;
    
    sbyte[] array = new sbyte[2];
    
    list.CopyTo(array, 0);
    

Now if you use a Select at any point, you don't end up with an ICollection<T>, so it goes through the legitimate (for the CLR) byte/sbyte conversion for each element, rather than trying to use the array implementation of CopyTo.

UPDATED WITH THE SOLUTION

Okay, this was very tricky. I have no idea how you manage to get this type of project. You might have upgraded your project type from an earlier version of ASP.NET MVC. Any way below is the answer.

In you Web.Config's runtime Assembly binding section, please add the below.

<dependentAssembly>
    <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
    <bindingRedirect oldVersion="1.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>

This should fix your problem.

You can use .Select(e => (Test)e).

You are trying to cast the array to int[] when it is a uint[]. That by itself is fine, since both int[] and uint[] are of type Array, and casting an Array object of type uint[] as an int[] (or vice versa) is allowed (for some reason).

The problem comes when you try to then convert it to a List. The method is trying to create a List of type int because that's the type you specified, but that's not what the type of the array actually is.

assembly.GetTypes() returns a RuntimeType[], but it uses array type covariance to disguise it as a Type[]. Per the docs for the Span constructor, an ArrayTypeMismatchException is thrown if T (which in this case is Type) does not match the runtime array type (which in this case is RuntimeType).

assembly.GetTypes().ToArray() on the other hand returns an actual Type[]: it will create a brand new array based on the declared type T, which is Type, so you get a true Type[] array and there is no mismatch -- T is Type and you're passing a true Type[] to the Span constructor.

ReadOnlySpan<T> does not have this constraint, since it is not possible to write an incompatible Type to a read-only RuntimeType[], so you can do this:

new ReadOnlySpan<Type>(assembly.GetTypes());