AsyncioIntegration hides an eager task factory from anyio, which breaks anyio task groups #7709
Description
How do you use Sentry?
Sentry Saas (sentry.io)
Version
2.70.0
Steps to Reproduce
Python 3.12 or later, anyio 4.8 or later.
import asyncio
import anyio
import sentry_sdk
from sentry_sdk.integrations.asyncio import AsyncioIntegration
async def child(event):
await event.wait()
async def main():
asyncio.get_running_loop().set_task_factory(asyncio.eager_task_factory)
sentry_sdk.init(integrations=[AsyncioIntegration()])
async with anyio.create_task_group() as tg:
tg.start_soon(child, anyio.Event())
await anyio.sleep(0.01)
tg.cancel_scope.cancel()
asyncio.run(main())Expected Result
The task group exits normally, as it does without AsyncioIntegration.
Actual Result
ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
RuntimeError: Attempted to exit a cancel scope that isn't the current tasks's current cancel scope
Cause
anyio starts the children of a task group non-eagerly, whatever the loop's task factory.
To do that it has to recognise an eager task factory, and asyncio offers no public way to ask.
anyio compares factory.__code__ with asyncio.eager_task_factory.__code__, which every factory returned by asyncio.create_eager_task_factory() shares, and then calls the task constructor from the factory's closure.
AsyncioIntegration replaces the loop's task factory with _sentry_task_factory, a plain function that calls the original.
Its code object is its own, so anyio takes it for an ordinary factory, the child starts eagerly inside create_task(), and anyio's bookkeeping for the task is written after the task has already run.
Proposed fix
When the original factory is an eager one, install a factory built with asyncio.create_eager_task_factory() and wrap the coroutine in its task constructor.
Tasks stay eager, spans are created as before, and anyio recognises the factory.
I have a patch with tests and can open a PR if this approach is acceptable.
Metadata
Metadata
Assignees
Projects
- StatusShow more project fieldsWaiting for: Community
Activity
linear-code commentedon Sep 24, 2026
PY-2889
ericapisani commentedon Sep 28, 2026
Hi @iainmcgin , thanks for opening an issue with us!
When using our SDK, we advise initializing it as early as possible in your application. When running your reproduction on my machine, I found that swapping the order of the
sentry_sdk.initandasyncio.get_running_loop()calls such thatasyncio.get_running_loop()comes first inmainresults in the program not raising the runtime error.Can you confirm if this addresses your original issue? Thanks!
getsantry commentedon Oct 21, 2026
This issue has gone three weeks without activity. In another week, I will close it.
But! If you comment or otherwise update it, I will reset the clock, and if you remove the label
Waiting for: Community, I will leave it alone ... forever!"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀