csharpseverity: workaround
InvalidCastException

C# InvalidCastException — Cannot cast object to incompatible type

InvalidCastException: specified cast is not valid

97% fixable~10 mindifficulty: beginner

Verified against .NET 8 documentation, C# language spec §10.3.2, CLR via C# by Jeffrey Richter · Updated June 2026

> quick_fix

Use the `as` operator instead of a direct cast for reference types — it returns null on failure instead of throwing. For value types, use `is` pattern matching to check the type before casting.

// BROKEN: direct cast throws if obj is not an Animal
Animal animal = (Animal)obj;

// FIXED option 1: as operator (returns null instead of throwing)
Animal? animal = obj as Animal;
if (animal != null) { /* safe to use */ }

// FIXED option 2: is pattern matching (C# 7+)
if (obj is Animal a)
{
    a.Speak(); // a is type-safe here
}

// FIXED option 3: switch expression (C# 8+)
string desc = obj switch
{
    Dog d    => d.Bark(),
    Cat c    => c.Meow(),
    _        => "unknown"
};

What causes this error

InvalidCastException is thrown by the CLR when a direct cast `(TargetType)obj` fails because the object is not actually of the target type or a derived type. It also occurs when trying to convert incompatible value types (e.g., casting a boxed int to a long — even though int fits in a long, the unbox must be to the exact type).

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Identify the actual type of the object

    Add a debug line before the cast: `Console.WriteLine(obj?.GetType().FullName ?? "null");`. Compare the actual type to the type you are casting to. If they are unrelated, you have the wrong object or the wrong target type.

  2. 02

    step 2

    Switch from direct cast to the as operator

    For reference types, replace `(Animal)obj` with `obj as Animal`. If the cast is invalid it returns null instead of throwing. Always check for null after `as`. This pattern is safe and performs the same MSIL `isinst` check as a direct cast.

  3. 03

    step 3

    Use is pattern matching for type checks + assignment

    C# 7+ pattern: `if (obj is Animal animal) { animal.Speak(); }`. This is the modern idiomatic replacement for `obj is Animal && (Animal)obj`. The pattern variable `animal` is scoped to the true branch and is guaranteed non-null.

  4. 04

    step 4

    Fix boxed value type casts

    A boxed `int` must be unboxed to exactly `int` — `(long)(object)someInt` throws InvalidCastException. The fix is `(long)(int)(object)someInt` — unbox to int first, then widen to long. This is the most surprising InvalidCastException case.

  5. 05

    step 5

    Use Convert class for numeric conversions

    For converting between numeric types where the types may differ, use `Convert.ToInt32(obj)`, `Convert.ToDouble(obj)` etc. These methods handle widening and narrowing conversions that direct casts cannot.

How to verify the fix

  • The cast no longer throws — add a unit test that passes an object of the expected type
  • Add a negative test — pass an incompatible type and verify graceful handling (null return or specific exception)
  • Run the application end-to-end through the code path that was casting

Why InvalidCastException happens at the runtime level

The CLR implements casts using the `castclass` and `isinst` IL instructions. `castclass` (used by direct C# casts) throws InvalidCastException if the object does not implement or inherit the target type. `isinst` (used by `as` and `is`) returns null or false instead of throwing. The boxed value type special case exists because the CLR stores the exact original type in the box header — there is no implicit widening at the unbox stage, unlike with implicit numeric conversions at the C# language level.

Common debug mistakes for InvalidCastException

  • Casting a boxed int to long directly — must unbox to int first, then convert
  • Using direct cast (T) on objects from collections typed as object or dynamic without verifying the runtime type first
  • Assuming that because type B extends A, a collection of A references can be directly cast to IList<B> (covariance doesn't work for mutable generic collections in C#)
  • Casting an enum to an incompatible underlying type (e.g., an int-backed enum value cast to a long-backed enum)

When InvalidCastException signals a deeper problem

InvalidCastException often surfaces in code that uses weakly-typed containers (object, dynamic, non-generic collections from pre-.NET 2.0 APIs) or when deserializing data where the schema is assumed but not validated. The systemic fix is to use generic types throughout, avoiding object and dynamic, and to validate deserialized data with strongly-typed DTOs before passing it into the domain layer.

Editor's take

InvalidCastException fires when the CLR cannot convert one type to another at runtime — you asked for a cast that the type system can't satisfy. The tricky part is that the C# compiler can't always catch these at compile time, especially when you're working with `object` references, COM interop, or loosely-typed data sources like DataReader. The classic production scenario: you call `(int)reader["age"]` but the database column is `bigint`, which maps to `long` in C#. The cast from `long` to `int` via an `object` intermediate fails at runtime even though both are numeric types. The fix is `Convert.ToInt32()` or explicit unboxing to the correct type first. In modern C# codebases, InvalidCastException most often appears when developers use the cast operator `(T)` instead of the `as` operator or pattern matching (`is T value`). The `as` operator returns null on failure instead of throwing, and pattern matching gives you a clean boolean check. If you're working with legacy code that passes everything as `object`, consider introducing generic methods to push type safety back to compile time. InvalidCastException is fundamentally a design smell — it means your code lost type information somewhere and is trying to recover it unsafely. The long-term fix is usually stronger typing, not more casts.

By Bikram Nath · Curator · Updated June 2026

Frequently asked questions

Why does (long)(object)5 throw InvalidCastException?

When you box an int (value 5), the CLR stores it as a boxed int in memory. Unboxing it requires you to unbox to the exact same type (int). Attempting (long)(object)5 tries to unbox directly to long, which fails because the box contains an int, not a long. The fix is to chain: (long)(int)(object)5.

What is the difference between InvalidCastException and a compile-time cast error?

The C# compiler catches casts that are statically provably impossible (e.g., casting int to string). InvalidCastException is thrown at runtime for casts that the compiler cannot rule out statically — typically casts through object or interface references where the actual runtime type is determined dynamically.

Should I use 'as' or direct cast?

Use 'as' when a failed cast is expected and you want null as the result. Use direct cast when a failed cast is a programming error and you want an exception immediately. Pattern matching with 'is' is the most modern approach and should be preferred in new C# code.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is cross-referenced against the official sources listed in the “sources” sidebar before it ships. If a fix here didn’t work for you, please email so we can update the page.