dotnet reflection_error ai_generated true

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.

ID: dotnet/target-invocation-exception

Also available as: JSON · Markdown
85%Fix Rate
88%Confidence
80Evidence
2023-01-01First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
8 active

Root Cause

TargetInvocationException is a wrapper exception thrown by .NET reflection APIs (MethodInfo.Invoke, Activator.CreateInstance, ConstructorInfo.Invoke, PropertyInfo.SetValue, etc.) when the invoked method or constructor throws an exception internally. The actual error is always in the InnerException. This exception is extremely common in DI containers, serialization frameworks, source generators at runtime, MVC model binding, and any framework that uses reflection to instantiate types or invoke methods. On .NET 8 Linux, additional causes include missing native dependencies during reflected constructor calls and trimming-related issues when using AOT compilation. Fix by inspecting InnerException, and where possible, replacing reflection with source generators or compile-time approaches.

generic

Workarounds

  1. 90% success Unwrap InnerException using ExceptionDispatchInfo to preserve the original stack trace
    Use ExceptionDispatchInfo to re-throw the inner exception while preserving its original stack trace: try { methodInfo.Invoke(target, args); } catch (TargetInvocationException ex) when (ex.InnerException != null) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); }. This gives you the actual exception type and the exact line where the failure occurred inside the invoked method. In logging scenarios: logger.LogError(ex.InnerException, "Reflected method {Method} failed", methodInfo.Name);
  2. 88% success Replace reflection-based invocation with compiled delegates or source generators
    For frequently invoked reflected methods, compile to a delegate once: var method = typeof(MyService).GetMethod("Process")!; var func = (Func<MyService, string, Task<Result>>)Delegate.CreateDelegate(typeof(Func<MyService, string, Task<Result>>), method); // Now calls through func() throw the original exception, not TargetInvocationException: var result = await func(service, input); For constructor invocation, use compiled expressions: var ctor = typeof(MyService).GetConstructor(new[] { typeof(ILogger) })!; var param = Expression.Parameter(typeof(ILogger)); var lambda = Expression.Lambda<Func<ILogger, MyService>>(Expression.New(ctor, param), param).Compile();
  3. 86% success Use the .NET 8 MethodInvoker or ConstructorInvoker APIs for better performance and exception handling
    In .NET 8, use the new MethodInvoker API that provides better performance and can optionally unwrap exceptions: var invoker = MethodInvoker.Create(methodInfo); try { invoker.Invoke(target, arg1, arg2); } catch (TargetInvocationException ex) { // Still wraps, but the invoker is significantly faster than MethodInfo.Invoke // Use ExceptionDispatchInfo to unwrap as needed ExceptionDispatchInfo.Capture(ex.InnerException!).Throw(); }. For constructors: var ctorInvoker = ConstructorInvoker.Create(constructorInfo); var instance = ctorInvoker.Invoke(arg1);

Dead Ends

Common approaches that don't work:

  1. Debugging based on the outer TargetInvocationException message and stack trace 85% fail

    The outer exception message is always the same generic string ('Exception has been thrown by the target of an invocation') and the outer stack trace points to the reflection infrastructure (MethodBase.Invoke, RuntimeMethodHandle.InvokeMethod), not to the actual failing code. All diagnostic information is in InnerException. Developers who do not unwrap the InnerException waste time investigating the reflection call site instead of the actual error location

  2. Catching TargetInvocationException and re-throwing without preserving the inner exception 80% fail

    Using 'throw ex.InnerException;' resets the stack trace, losing the original call site information. Using 'throw;' re-throws the TargetInvocationException wrapper, which is not helpful. Both approaches lose critical debugging information. The correct unwrapping requires ExceptionDispatchInfo to preserve the original stack trace

  3. Adding [DebuggerStepThrough] or [DebuggerHidden] attributes to suppress the exception in the debugger 95% fail

    These attributes only affect the debugger experience and do not fix the underlying exception. The TargetInvocationException still occurs at runtime. In production, the same error will crash the application or produce incorrect behavior. These attributes just make the error harder to diagnose during development

Error Chain

Leads to:
Preceded by:
Frequently confused with: