Skip to content

Using isolation scopes with multiple depths of generators causes Token was created in different Context error #4925

@ntindle

Description

@ntindle

How do you use Sentry?

Sentry Saas (sentry.io)

Version

2.33.2

Steps to Reproduce

#!/usr/bin/env python3
"""
Minimal reproduction case for Sentry isolation_scope + async generator bug.

Bug: Using sentry_sdk.isolation_scope() as a context manager around an async
generator that yields causes "Token was created in a different Context" error
when the generator exits early (via break, exception, or garbage collection).
"""

import asyncio
import sentry_sdk
from sentry_sdk.integrations.asyncio import AsyncioIntegration


async def inner_generator():
    """Simple async generator that yields values"""
    for i in range(3):
        print(f"  Inner generator yielding: {i}")
        yield i


async def problematic_async_generator():
    """
    This pattern causes the context error.
    The isolation_scope wraps yield statements in an async generator.
    """
    with sentry_sdk.isolation_scope() as scope:
        scope.set_user({"id": "test-user-123"})
        scope.set_tag("example", "value")

        async for value in inner_generator():
            # THIS YIELD INSIDE ISOLATION_SCOPE IS THE PROBLEM
            yield value


async def main():
    print("Reproducing Sentry isolation_scope + async generator bug\n")
    print("=" * 60)

    # Initialize Sentry
    sentry_sdk.init(
        dsn=None,  # No DSN needed to reproduce
        integrations=[AsyncioIntegration()],
        debug=True,
    )

    print("Test 1: Normal completion (works fine)")
    print("-" * 40)
    async for val in problematic_async_generator():
        print(f"Received: {val}")
    print("✅ No error when generator completes normally\n")

    print("Test 2: Early exit with break (causes error)")
    print("-" * 40)
    async for val in problematic_async_generator():
        print(f"Received: {val}")
        if val == 1:
            print("Breaking early...")
            break  # This causes the context error

    # Give time for error to appear in output
    await asyncio.sleep(0.1)
    print("\n❌ Error appears above: 'Token was created in a different Context'")

    print("\n" + "=" * 60)
    print("The error happens because:")
    print("1. isolation_scope() saves the current context when entering")
    print("2. The async generator suspends/resumes across context boundaries")
    print("3. When exiting early, cleanup happens in a different context")
    print("4. Python's contextvars raises ValueError")


if __name__ == "__main__":
    asyncio.run(main())

Expected Result

Not to crash

Actual Result

Test 2: Early exit with break (causes error)
----------------------------------------
  Inner generator yielding: 0
Received: 0
  Inner generator yielding: 1
Received: 1
Breaking early...
Task exception was never retrieved
future: <Task finished name='coroutine without __name__ (Sentry-wrapped)' coro=<patch_asyncio.<locals>._sentry_task_factory.<locals>._task_with_sentry_span_creation() done, defined at /Users/ntindle/Library/Caches/pypoetry/virtualenvs/autogpt-platform-backend-90-hPFvq-py3.12/lib/python3.12/site-packages/sentry_sdk/integrations/asyncio.py:42> exception=ValueError("<Token var=<ContextVar name='current_scope' default=None at 0x1033a7790> at 0x109af7300> was created in a different Context")>
Traceback (most recent call last):
  File "/Users/ntindle/Library/Caches/pypoetry/virtualenvs/autogpt-platform-backend-90-hPFvq-py3.12/lib/python3.12/site-packages/sentry_sdk/scope.py", line 1755, in isolation_scope
    yield new_isolation_scope
  File "/Users/ntindle/code/agpt/AutoGPT/main/autogpt_platform/backend/./sentry_bug_repro.py", line 33, in problematic_async_generator
    yield value
GeneratorExit

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/ntindle/Library/Caches/pypoetry/virtualenvs/autogpt-platform-backend-90-hPFvq-py3.12/lib/python3.12/site-packages/sentry_sdk/integrations/asyncio.py", line 55, in _task_with_sentry_span_creation
    reraise(*_capture_exception())
  File "/Users/ntindle/Library/Caches/pypoetry/virtualenvs/autogpt-platform-backend-90-hPFvq-py3.12/lib/python3.12/site-packages/sentry_sdk/utils.py", line 1751, in reraise
    raise value
  File "/Users/ntindle/Library/Caches/pypoetry/virtualenvs/autogpt-platform-backend-90-hPFvq-py3.12/lib/python3.12/site-packages/sentry_sdk/integrations/asyncio.py", line 53, in _task_with_sentry_span_creation
    result = await coro
             ^^^^^^^^^^
  File "/Users/ntindle/code/agpt/AutoGPT/main/autogpt_platform/backend/./sentry_bug_repro.py", line 27, in problematic_async_generator
    with sentry_sdk.isolation_scope() as scope:
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/Users/ntindle/Library/Caches/pypoetry/virtualenvs/autogpt-platform-backend-90-hPFvq-py3.12/lib/python3.12/site-packages/sentry_sdk/scope.py", line 1760, in isolation_scope
    _current_scope.reset(current_token)
ValueError: <Token var=<ContextVar name='current_scope' default=None at 0x1033a7790> at 0x109af7300> was created in a different Context

❌ Error appears above: 'Token was created in a different Context'

Workaround

Save the scope user and tags, then manually catch the error in the generator using capture_exception, then set the tags using scope._tags = previous

Metadata

Metadata

Assignees

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions