Skip to content

Keep the failing delegate's stack trace when Invoke rethrows - #55

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/preserve-invoke-stack-trace
Sep 26, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/preserve-invoke-stack-trace

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #54

What changed

When a delegate was marshalled to the owner thread and threw, both synchronous Invoke overloads unwrapped the AggregateException and rethrew it with throw ex.InnerException. That resets the stack trace to Invoker.Invoke. Now both overloads call InvokeAsync(func).GetAwaiter().GetResult(), which rethrows the original exception with its stack trace intact. This also removes the try/catch.

Tests

  • Added InvokeActionFromOtherThreadShouldPreserveStackTraceOfFailingCode and InvokeFunctionFromOtherThreadShouldPreserveStackTraceOfFailingCode. Each calls Invoke from a worker thread while the owner thread pumps DoInvokes. The delegate throws from a named NoInlining helper, and the test asserts that the helper's name appears in the caught exception's StackTrace.
  • With the fix reverted, both tests fail: the trace starts at Invoker.Invoke.
  • Full suite: 21/21 pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NHprKRwyYopkJnUyhF3KSr


Generated by Claude Code

Invoke unwrapped the AggregateException from Wait()/.Result and rethrew
the inner exception with `throw`, which resets its stack trace to
Invoker.Invoke. Cross-thread failures lost every frame of the code that
actually failed. Both overloads now use GetAwaiter().GetResult(), which
rethrows the original exception with its trace intact.

Fixes #54

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NHprKRwyYopkJnUyhF3KSr
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 593c9f3 into main Sep 26, 2026
12 checks passed
@matt-edmondson
matt-edmondson deleted the fix/preserve-invoke-stack-trace branch September 26, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invoke() rethrows the inner exception with throw ex.InnerException, discarding the stack trace of the code that actually failed

2 participants