C# InvalidCastException: specified cast is not valid
Fix C# InvalidCastException when an explicit cast targets the wrong type, and use pattern matching or as-cast for safe conversion.
Symptoms
- System.InvalidCastException: Unable to cast object of type X to type Y
- A cast that worked for one value fails for another
- Unboxing an object to the wrong value type throws
Possible causes
- An object reference is cast to an unrelated type
- An object stored as object is unboxed to the wrong value type
- A collection contains heterogeneous types
- A serialization or DI type changed but the cast was not updated
Diagnosis steps
Read the runtime types from the message
Interpretation
It names both the actual type and the attempted target, showing exactly where they diverge.
Use pattern matching instead of a cast
if (obj is string s) { ... }Interpretation
is-patterns succeed only when the type matches, avoiding the exception.
Trace the value origin
Interpretation
Boxing, deserialization, and DI often deliver a base or object type that needs checking before use.
Root cause
An explicit cast asserts the runtime type. When the object is a different type, the CLR throws InvalidCastException — there is no conversion performed. This differs from numeric conversion, which uses Convert or Parse. Boxed value types must be unboxed to their exact type.
Fix
Use `as` with a null check or `is` pattern matching to test type before use, and use Convert/Parse for numeric conversions. In collections, prefer generics so element types are known. When deserialising or resolving from DI, request the concrete type or validate with pattern matching before casting.
Verify the fix
Re-run with a value of the previously failing type; the pattern-matched branch handles it without throwing, and a test covers both matching and non-matching types.
Symptoms
A cast throws InvalidCastException: Unable to cast object of type 'X' to type 'Y'. It often appears only for certain inputs, such as a boxed int where a long was expected.
Diagnosis
Note the two types in the message and inspect the value:
object boxed = 42; // boxed int
long l = (long)boxed; // InvalidCastException
Boxed value types must be unboxed to their exact type.
Fix
Use pattern matching and proper numeric conversion:
if (obj is string s) {
Handle(s);
}
object boxed = 42;
long l = Convert.ToInt64(boxed); // correct numeric conversion
Prefer generics over object collections.
Verification
Re-run with the offending value; the pattern branch or conversion succeeds. A test asserts both a matching and a non-matching type path.
Additional Notes
The message names both runtime types, which is the fastest clue: a boxed integer cast to long, or a base type cast to an unrelated derived type, both fail identically even though the intent differs. Numeric widening needs a proper conversion rather than an explicit narrowing cast, while reference conversions need pattern matching. Enabling nullable reference types and preferring generics over object collections removes most such casts entirely, because the compiler then knows element types and flags unsafe conversions before the code ever runs.