Async SQLite hang in Codex runtime (aiosqlite + SQLAlchemy)
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_spawnawaits 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) andsqlalchemy(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.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗