Async SQLite hang in Codex runtime (aiosqlite + SQLAlchemy)

Open 💬 4 comments Opened Jan 26, 2026 by aphronio

Summary

In the Codex execution environment, async SQLite connections using aiosqlite hang when used through SQLAlchemy async (sqlite+aiosqlite). The same code runs fine in a normal interactive terminal on the same machine (Python 3.13.9, uv, same dependencies).

This appears to be a runtime/environment interaction (Codex command runner) rather than a project bug. It only reproduces when network access is disabled by the sandbox and does not reproduce when network access is enabled.

Environment

  • Codex execution environment (non-interactive command runner)
  • Codex CLI: 0.91.0
  • OS: Arch Linux (kernel 6.18.3-arch1-1, x86_64)
  • Python: 3.13.9 (uv managed)
  • aiosqlite: 0.21.0
  • SQLAlchemy: 2.0.44
  • greenlet: 3.2.4

Repro (hangs in Codex runtime)

uv run --extra test python -u - <<'PY'
import asyncio
from sqlalchemy.ext.asyncio import create_async_engine

async def main():
    engine = create_async_engine("sqlite+aiosqlite:///:memory:", future=True)
    print("engine created")
    async with engine.connect():
        print("connected")
    await engine.dispose()

asyncio.run(main())
PY

Expected: prints "connected". Actual in Codex runtime: prints "engine created" and hangs.

Control (works in normal terminal)

This script works when run in a standard terminal (outside Codex runner):

uv run --extra test python -u - <<'PY'
import asyncio
import aiosqlite
from sqlalchemy import text
from sqlalchemy.ext.asyncio import create_async_engine

async def main():
    print("aiosqlite connect start")
    async with aiosqlite.connect(":memory:") as db:
        await db.execute("select 1")
    print("aiosqlite connect ok")

    print("sqlalchemy async connect start")
    engine = create_async_engine("sqlite+aiosqlite:///:memory:", future=True)
    async with engine.connect() as conn:
        await conn.execute(text("select 1"))
    await engine.dispose()
    print("sqlalchemy async connect ok")

asyncio.run(main())
PY

Instrumentation findings

Instrumentation inside aiosqlite.core.Connection shows:

  • The background thread executes the connector and calls future.set_result(...) successfully.
  • The Future is marked done and its done-callback fires.
  • The awaiting coroutine in _connect() never resumes and eventually times out.

Key logs (abbreviated):

thread executing connector ...
thread function result <sqlite3.Connection ...>
thread scheduled set_result
future done callback True cancelled False
await failed TimeoutError

The hang occurs inside SQLAlchemy's async path:

  • AsyncConnection.start() -> greenlet_spawn(self.sync_engine.connect)
  • greenlet_spawn awaits the aiosqlite Connection awaitable and never resumes.

This suggests a subtle interaction between the Codex runner event loop, greenlet-based SQLAlchemy async bridge, and aiosqlite's thread handoff.

Additional datapoint (sync works)

Synchronous SQLite works in the Codex environment:

engine created
connected
executed
done

This further points to the async path specifically. One hypothesis is that aiosqlite's background-thread handoff (via loop.call_soon_threadsafe) interacts poorly with the Codex sandbox/event-loop setup. I don't yet have a minimal repro that fails in all Codex contexts, so treat this as a working theory rather than a confirmed root cause.

Network access toggles the hang

With network access enabled in this Codex environment, the hang does not reproduce.
With network access revoked (default sandbox restrictions), the hang reproduces.

Last verified

2026-01-26

Notes

  • Bumping aiosqlite (0.22.1) and sqlalchemy (2.0.46) did not fix it in the Codex runtime.
  • The same dependencies work in a normal terminal (non-Codex runner).

Impact

Async SQLite usage (via sqlite+aiosqlite) hangs under the Codex runner when sandbox network access is disabled, preventing test execution.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗