Summary
All sync APIs that route through inspect_ai._util._async.run_coroutine (read_eval_log, list_eval_logs, the inspect_ai.analysis dataframe builders, Inspect Scout's scan(), ...) corrupt the kernel event loop when called from a Jupyter notebook running ipykernel >= 7. In a notebook, run_coroutine applies nest_asyncio2 and calls asyncio.run() on top of the kernel's running loop. ipykernel 7 (released 2025-10-13, now the default install) rewrote message handling as anyio tasks with per-message contexts (Kernel.shell_main, _async_in_context), and nest_asyncio's re-entrant loop running is incompatible with that.
Note the failure is noisy rather than always fatal — cells often still return correct results beneath the error spew — but the nest_asyncio2.apply() patch is process-global, so a single sync call degrades the kernel for the rest of the session. (This may be why it's gone unreported.)
Symptoms
ERROR Exception in callback Task.__step()
RuntimeError: cannot enter context: <_contextvars.Context object at 0x...> is already entered
ERROR Task was destroyed but it is pending!
task: <Task pending name='Task-24' coro=<Kernel.shell_main() running at .../ipykernel/kernelbase.py:597>
RuntimeWarning: coroutine 'Kernel.shell_main' was never awaited
Errors recur on later cells, including cells that don't touch inspect_ai.
Repro
inspect-ai 0.3.246, nest-asyncio2 1.7.2, Python 3.12, macOS
ipykernel 7.3.0 -> corrupted (above errors)
ipykernel 6.31.0 -> clean (same code)
pip install inspect-ai "ipykernel>=7" jupyterlab
- In a notebook cell, call any sync log API, e.g.
from inspect_ai.log import list_eval_logs; list_eval_logs("logs/") (any log dir).
- Errors appear in that cell's output and in subsequent cells.
Scriptable repro (no live Jupyter needed): execute a two-cell notebook via nbclient — cell 1 calls a sync API, cell 2 is import time; time.sleep(2) — and grep the outputs for Task was destroyed / cannot enter context.
Found while running transcript analysis in JupyterLab.
Summary
All sync APIs that route through
inspect_ai._util._async.run_coroutine(read_eval_log,list_eval_logs, theinspect_ai.analysisdataframe builders, Inspect Scout'sscan(), ...) corrupt the kernel event loop when called from a Jupyter notebook running ipykernel >= 7. In a notebook,run_coroutineappliesnest_asyncio2and callsasyncio.run()on top of the kernel's running loop. ipykernel 7 (released 2025-10-13, now the default install) rewrote message handling as anyio tasks with per-message contexts (Kernel.shell_main,_async_in_context), and nest_asyncio's re-entrant loop running is incompatible with that.Note the failure is noisy rather than always fatal — cells often still return correct results beneath the error spew — but the
nest_asyncio2.apply()patch is process-global, so a single sync call degrades the kernel for the rest of the session. (This may be why it's gone unreported.)Symptoms
Errors recur on later cells, including cells that don't touch inspect_ai.
Repro
pip install inspect-ai "ipykernel>=7" jupyterlabfrom inspect_ai.log import list_eval_logs; list_eval_logs("logs/")(any log dir).Scriptable repro (no live Jupyter needed): execute a two-cell notebook via
nbclient— cell 1 calls a sync API, cell 2 isimport time; time.sleep(2)— and grep the outputs forTask was destroyed/cannot enter context.Found while running transcript analysis in JupyterLab.