Skip to content

Fix DeferAsync async handler nesting bug in CommandAsync#7999

Merged
Arkatufus merged 4 commits into
akkadotnet:devfrom
Aaronontheweb:fix/defer-async-nesting-bug
Jan 21, 2026
Merged

Fix DeferAsync async handler nesting bug in CommandAsync#7999
Arkatufus merged 4 commits into
akkadotnet:devfrom
Aaronontheweb:fix/defer-async-nesting-bug

Conversation

@Aaronontheweb
Copy link
Copy Markdown
Member

Summary

Fixes #7998

  • Fixed DeferAsync with async handler throwing "RunTask calls cannot be nested" when called from within a CommandAsync handler after an await, when there are no pending persist operations
  • Added regression tests to verify the fix

Root Cause

The async handler version of DeferAsync had an optimization that immediately executed the handler via RunTask() when _pendingInvocations.Count == 0. When called from within a CommandAsync handler (which is already in a RunTask context), this caused the nesting exception.

Fix

Always queue async handlers to _pendingInvocations instead of attempting immediate execution. The handler executes via PeekApplyHandler after the command handler completes, safely outside any existing RunTask context.

Test plan

  • Added regression test for DeferAsync with async handler from CommandAsync (no prior persist)
  • Added test for DeferAsync with sync handler from CommandAsync (verify still works)
  • Added test for DeferAsync with async handler after PersistAsync (verify queuing path works)
  • All persistence tests pass (284 passed, 3 skipped)
  • API compatibility tests pass (17 passed)

…7998)

DeferAsync with an async handler threw "RunTask calls cannot be nested"
when called from within a CommandAsync handler after an await, when there
were no pending persist operations.

The fix removes the immediate RunTask execution optimization for async
handlers and always queues them to _pendingInvocations. This avoids the
nesting issue since the handler executes after the command handler
completes.

Added regression tests to verify the fix.
Copy link
Copy Markdown
Member Author

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detailed my changes


if (_pendingInvocations.Count == 0)
{
RunTask(() => handler(evt));
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was my bad - added this as part of #7937 , but this was wrong

Copy link
Copy Markdown
Contributor

@Arkatufus Arkatufus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Arkatufus Arkatufus merged commit 424e09d into akkadotnet:dev Jan 21, 2026
12 checks passed
Aaronontheweb added a commit to Aaronontheweb/akka.net that referenced this pull request Jan 26, 2026
…7998) (akkadotnet#7999)

DeferAsync with an async handler threw "RunTask calls cannot be nested"
when called from within a CommandAsync handler after an await, when there
were no pending persist operations.

The fix removes the immediate RunTask execution optimization for async
handlers and always queues them to _pendingInvocations. This avoids the
nesting issue since the handler executes after the command handler
completes.

Added regression tests to verify the fix.
Aaronontheweb added a commit that referenced this pull request Jan 26, 2026
DeferAsync with an async handler threw "RunTask calls cannot be nested"
when called from within a CommandAsync handler after an await, when there
were no pending persist operations.

The fix removes the immediate RunTask execution optimization for async
handlers and always queues them to _pendingInvocations. This avoids the
nesting issue since the handler executes after the command handler
completes.

Added regression tests to verify the fix.
This was referenced May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DeferAsync with async handler throws 'RunTask calls cannot be nested' when called from CommandAsync

2 participants