C# exception
type conversion error
nullable types
System.Int32
debugging tips

Invalid cast from 'System.Int32' to 'System.Nullable1System.Int32, mscorlib

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

This exception usually appears in reflection, data mapping, or generic conversion code that operates on object and Type values at runtime. In ordinary C# assignments, int and int? work together naturally, but runtime conversion APIs do not automatically wrap an int into Nullable<int> the way the compiler does.

That distinction is the whole problem. The language understands nullable conversions, while a generic conversion helper such as Convert.ChangeType generally does not.

Why the Cast Fails

At compile time, this is fine:

csharp
int value = 42;
int? maybeValue = value;

The compiler inserts the correct nullable conversion.

But runtime code often looks more like this:

csharp
object raw = 42;
Type targetType = typeof(int?);

If you then call Convert.ChangeType(raw, targetType), it can fail because Nullable<int> is not treated as an ordinary primitive conversion target.

There is also a boxing detail behind this: when int? has a value, boxing usually boxes the underlying int, not a special nullable wrapper object. So a runtime mapper often sees System.Int32 and then has to decide how to build int? from it.

Convert the Underlying Type First

The usual fix is:

  1. check whether the target type is nullable
  2. extract the underlying type with Nullable.GetUnderlyingType
  3. convert to that underlying type
  4. return null for null or DBNull.Value
csharp
1using System;
2
3public static class NullableConverter
4{
5    public static object? ChangeType(object? value, Type targetType)
6    {
7        if (value is null || value == DBNull.Value)
8        {
9            return null;
10        }
11
12        Type underlying = Nullable.GetUnderlyingType(targetType) ?? targetType;
13
14        if (underlying.IsInstanceOfType(value))
15        {
16            return value;
17        }
18
19        return Convert.ChangeType(value, underlying);
20    }
21}
22
23public class Program
24{
25    public static void Main()
26    {
27        object raw = "42";
28        int? result = (int?)NullableConverter.ChangeType(raw, typeof(int?));
29        Console.WriteLine(result);
30    }
31}

The conversion works because the runtime converts to int, not directly to int?.

Reflection and Property Setters Need the Same Pattern

This exception is common when populating object properties dynamically.

csharp
1using System;
2using System.Reflection;
3
4public class Person
5{
6    public int? Age { get; set; }
7}
8
9object raw = "35";
10var person = new Person();
11PropertyInfo property = typeof(Person).GetProperty(nameof(Person.Age))!;
12object? converted = NullableConverter.ChangeType(raw, property.PropertyType);
13property.SetValue(person, converted);
14
15Console.WriteLine(person.Age);

If you skip the nullable-unwrapping step and pass property.PropertyType directly into a generic conversion API, you are likely to hit the exception again.

DBNull.Value Needs Explicit Handling

Database code is another common source of this problem. DBNull.Value is not the same thing as null, and if you treat them as identical only sometimes, nullable mapping bugs follow quickly.

A typed data-reader approach is often safer than broad runtime conversion:

csharp
int ordinal = reader.GetOrdinal("Age");
int? age = reader.IsDBNull(ordinal) ? null : reader.GetInt32(ordinal);

When you know the source schema, direct typed access is simpler, faster, and less fragile than a generalized conversion pipeline.

Prefer Strong Typing When You Can

The deeper lesson is that runtime conversion should live at boundaries, not all through the codebase. If the application can get into strong types early, nullable conversions stop being mysterious because the compiler handles them naturally.

Generic mappers are useful, but they need explicit nullable handling. Otherwise they end up reinventing pieces of the type system badly.

Common Pitfalls

The biggest mistake is calling Convert.ChangeType(value, typeof(int?)) and expecting it to behave like a normal C# assignment. Another is forgetting about DBNull.Value in data-access code. Developers also sometimes overuse generic runtime conversion even when the source schema is known and a typed accessor would be clearer. Finally, a boxed nullable with a value often appears as the underlying non-nullable type, which surprises people who expect runtime type checks to preserve the source syntax.

Summary

  • This exception is a runtime conversion issue, not a normal C# assignment issue.
  • 'Convert.ChangeType usually converts to the underlying type such as int, not directly to int?.'
  • Unwrap nullable targets with Nullable.GetUnderlyingType before converting.
  • Treat null and DBNull.Value explicitly in mapping code.
  • Prefer typed access at boundaries when the source schema is already known.

Course illustration
Course illustration

All Rights Reserved.