{"record":{"id":"f8e9237d2fd5f959","repo":"aio-libs/aiohttp","slug":"timeout-context-manager-should-be-used-inside-a-ta","errorCode":null,"errorMessage":"Timeout context manager should be used inside a task","messagePattern":"Timeout context manager should be used inside a task","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"aiohttp/helpers.py","lineNumber":705,"sourceCode":"    \"\"\"Low resolution timeout context manager\"\"\"\n\n    __slots__ = (\"_loop\", \"_tasks\", \"_cancelled\", \"_cancelling\")\n\n    def __init__(self, loop: asyncio.AbstractEventLoop) -> None:\n        self._loop = loop\n        self._tasks: list[asyncio.Task[Any]] = []\n        self._cancelled = False\n        self._cancelling = 0\n\n    def assert_timeout(self) -> None:\n        \"\"\"Raise TimeoutError if timer has already been cancelled.\"\"\"\n        if self._cancelled:\n            raise asyncio.TimeoutError from None\n\n    def __enter__(self) -> BaseTimerContext:\n        task = asyncio.current_task(loop=self._loop)\n        if task is None:\n            raise RuntimeError(\"Timeout context manager should be used inside a task\")\n\n        if sys.version_info >= (3, 11):\n            # Remember if the task was already cancelling\n            # so when we __exit__ we can decide if we should\n            # raise asyncio.TimeoutError or let the cancellation propagate\n            self._cancelling = task.cancelling()\n\n        if self._cancelled:\n            raise asyncio.TimeoutError from None\n\n        self._tasks.append(task)\n        return self\n\n    def __exit__(\n        self,\n        exc_type: type[BaseException] | None,\n        exc_val: BaseException | None,\n        exc_tb: TracebackType | None,","sourceCodeStart":687,"sourceCodeEnd":723,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/helpers.py#L687-L723","documentation":"BaseTimerContext.__enter__ raises RuntimeError when asyncio.current_task() returns None — meaning the timeout context manager is being used outside an asyncio task. The timeout() helper relies on task-level cancellation mechanics, so it requires an active task in the event loop.","triggerScenarios":"Using aiohttp.timeout() or the internal TimerContext in synchronous code, in a callback scheduled with loop.call_soon (which has no task), or before the event loop is running. Also triggered when using timeout in a thread that has no asyncio task context.","commonSituations":"Calling client code with timeout in a non-async function; using timeout in asyncio.ensure_future callbacks that are not wrapped in a coroutine; testing async code with pytest but calling timeout synchronously in a fixture; calling from a sync callback registered via add_done_callback.","solutions":["Ensure the timeout context manager is used inside an async function that runs as a task","Wrap synchronous callbacks in a coroutine before using timeout","Use asyncio.run() or loop.run_until_complete() to establish a task context"],"exampleFix":"# before (no task context)\ndef callback():\n    with timeout(10):\n        do_work()  # RuntimeError\n\n# after (inside a task)\nasync def fetch():\n    async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:\n        return await session.get(url)\n\nasyncio.run(fetch())","handlingStrategy":"validation","validationCode":"import asyncio, sys\n\ndef ensure_task_context():\n    if sys.version_info >= (3, 11):\n        task = asyncio.current_task()\n    else:\n        task = asyncio.current_task()\n    if task is None:\n        raise RuntimeError('timeout() must be called from within an asyncio task')\n    return task","typeGuard":null,"tryCatchPattern":"try:\n    with timeout(10):\n        await do_work()\nexcept RuntimeError as e:\n    if 'inside a task' in str(e):\n        # Re-run within a proper task\n        await asyncio.ensure_future(do_work_with_timeout())\n    raise","preventionTips":["Always use timeout() inside async functions that are awaited as tasks","Never call timeout() from synchronous callbacks or fixtures","Use pytest-asyncio or asyncio.run() to ensure task context in tests"],"tags":["timeout","asyncio","task","event-loop","runtime-error"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}