Skip to content

Python: Move away from nest_async (is not compatible with modern Python) and is unmaintained. #591

@whardier

Description

@whardier

Uvicorn is expecting a function signature that includes a loop_factory in Python3.12 - and nest_async is unfortunately patching the function and does not incorporate that feature and argument.

Sadly the project is no longer maintained.. see findings below (unverified)

... .venv/lib/python3.12/site-packages/uvicorn/server.py", line 67, in run
    return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
TypeError: _patch_asyncio.<locals>.run() got an unexpected keyword argument 'loop_factory'

Here's what Claude says:

● Now I can see the issue. nest_asyncio's patched run() function (line 25) only accepts (main, *, debug=False) — it doesn't support the loop_factory parameter that
Python 3.12+ and modern uvicorn use. But who's calling nest_asyncio.apply()? Let me check cdp's transitive imports.

● Read 1 file (ctrl+o to expand)

● Explore(Find nest_asyncio.apply caller)
⎿  Done (12 tool uses · 18.4k tokens · 20s)

● Found it. The culprit is cdp/evm_local_account.py. Let me confirm.

● Read 1 file (ctrl+o to expand)

● Here's the root cause:

cdp/evm_local_account.py:16 calls nest_asyncio.apply() at module import time (line 16). This is loaded because cdp/init.py imports EvmLocalAccount from this
module (line 7 of cdp/init.py).

When you from cdp.x402 import create_facilitator_config, Python first initializes the cdp package by running cdp/init.py, which imports EvmLocalAccount, which
triggers nest_asyncio.apply().

nest_asyncio.apply() monkey-patches asyncio.run with a replacement that has the signature run(main, *, debug=False) — it does not accept the loop_factory keyword
argument that was added in Python 3.12. Modern uvicorn passes loop_factory=... to asyncio.run, so it crashes with:

TypeError: _patch_asyncio..run() got an unexpected keyword argument 'loop_factory'

The fix options:

  1. Reorder imports — move uvicorn.run() before the cdp.x402 import isn't practical since you need the app built first.
  2. Lazy import — defer the cdp.x402 import so it doesn't run at module level, or import it only where needed.
  3. Upgrade nest_asyncio — version 1.6.0 is installed but it's outdated and doesn't support loop_factory. However, as of the last release, this was never fixed
    upstream.
  4. Patch around it — re-save the original asyncio.run before the cdp import and restore it after:

import asyncio
_original_run = asyncio.run

from cdp.x402 import create_facilitator_config # triggers nest_asyncio.apply()

asyncio.run = _original_run # restore the real asyncio.run

Option 4 is the most straightforward workaround. Want me to apply it to server.py?

✻ Cooked for 2m 1s

❯ what version of python is nest_ayncio meant to support.. because 3.12 isn't it.

● Read 1 file (ctrl+o to expand)

● It actually claims to support 3.12 (line 20 of the metadata). But that's a lie — or at least incomplete. The classifiers say 3.12, but the actual code was never
updated for the loop_factory parameter that was added to asyncio.run() in Python 3.12 (via
https://peps.python.org/pep-0690//https://github.com/python/cpython/issues/89943).

Look at their patched run() in nest_asyncio.py:25:

def run(main, *, debug=False):

The real asyncio.run signature since Python 3.12 is:

def run(main, *, debug=None, loop_factory=None):

The project is also effectively abandoned — the author (erdewit) passed away, and the repo at github.com/erdewit/nest_asyncio hasn't seen updates since. Version
1.6.0 was the last release (Jan 2024), and this loop_factory incompatibility was a known open issue that was never fixed.

So the real problem is that the cdp-sdk package depends on a dead library with a broken asyncio monkey-patch, and it applies it unconditionally at import time.
This is a bug in the cdp-sdk package — worth filing an issue with Coinbase's CDP SDK.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions