Skip to content

Python Workers: NoGilError race condition during concurrent request initialization (preparePython) #6624

@cooperjbrandon

Description

@cooperjbrandon

Bug Description

Python Workers using FastAPI throw NoGilError: Attempted to use PyProxy when Python GIL not held when multiple concurrent HTTP requests hit the same isolate. The error occurs in the runtime's preparePython/initPyInstance code path — not in application code.

Stack Trace

NoGilError: Attempted to use PyProxy when Python GIL not held
    at throw_no_gil (pyodide-internal:generated/emscriptenSetup:20688:13)
    at wasm://wasm/020fb45e:wasm-function[432]:0x117f9b
    at python_getattr (pyodide-internal:generated/emscriptenSetup:23035:13)
    at Object.get (pyodide-internal:generated/emscriptenSetup:23106:119)
    at async preparePython (pyodide:python-entrypoint-helper:202:28)
    at async initPyInstance (pyodide:python-entrypoint-helper:258:24)
    at async Proxy.<anonymous> (pyodide:python-entrypoint-helper:300:36)

Reproduction

  1. Deploy a Python Worker with FastAPI that makes async HTTP calls
  2. Send 3-5 concurrent requests to different endpoints on the same worker
  3. Observe NoGilError on some requests, with outcome exception

The error is more likely when:

  • Requests involve CPU-bound work
  • Multiple requests arrive within the same ~100ms window
  • The isolate is handling concurrent requests in stateless execution mode

Environment

  • compatibility_date: 2025-12-01 NOTE I just bumped my compat date to 2026-04-01, so perhaps that will help too.
  • compatibility_flags: ["python_workers"]
  • Execution model: stateless
  • Observed in deployed staging environment (not local dev)

Analysis

The race condition appears to be in the isolate re-use logic. When a second request arrives while the first is awaiting I/O (GIL released), preparePython for the second request tries to access a Python proxy object, but the GIL acquisition fails — likely because the first request's coroutine is resuming or the V8 snapshot restoration leaves the GIL in an inconsistent state.

All application code uses async/await correctly (no threading, no blocking I/O). The error is entirely within pyodide-internal and python-entrypoint-helper.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions