uvicorn icon indicating copy to clipboard operation
uvicorn copied to clipboard

unexpected keyword argument 'loop_factory' on uvicorn.run(), only when debugging

Open Kludex opened this issue 2 months ago • 12 comments

Discussed in https://github.com/Kludex/uvicorn/discussions/2736

Originally posted by sm-Fifteen October 21, 2025 I was about to file this as an issue, but it's not 100% clear if this is specifically Uvicorn's fault, here.

One way by which I commonly launch my apps is with a launch script that merely calls uvicorn.run(app, host="0.0.0.0", port=cfg.api_port, root_path=cfg.path_prefix), as per documentation documentation. I've recently been unable to use that path for debugging, as launching the Python debugger on this application causes an exception to be raised:

.venv\Scripts\python.exe PyCharm/plugins/python-ce/helpers/pydev/pydevd.py --multiprocess --qt-support=auto --client 127.0.0.1 --port 54848 --file launch.py 
Connected to: <socket.socket fd=1160, family=2, type=1, proto=0, laddr=('127.0.0.1', 54849), raddr=('127.0.0.1', 54848)>.
Connected to pydev debugger (build 252.26830.99)

Traceback (most recent call last):
  File "PyCharm\plugins\python-ce\helpers\pydev\pydevd.py", line 1648, in _exec
    pydev_imports.execfile(file, globals, locals)  # execute the script
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "PyCharm\plugins\python-ce\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "launch.py", line 17, in <module>
    uvicorn.run(app, host="0.0.0.0", port=cfg.api_port, root_path=cfg.path_prefix, log_config="./logconfig.json")
  File ".venv\Lib\site-packages\uvicorn\main.py", line 593, in run
    server.run()
  File ".venv\Lib\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'

The error is coming out of here: https://github.com/Kludex/uvicorn/blob/3850ad6520cafb290bd4174fa9c4ca5d33440c82/uvicorn/server.py#L66-L67

...and I'm using Python 3.12.11, so asyncio_run is supposed to be the regular one: https://github.com/Kludex/uvicorn/blob/3850ad6520cafb290bd4174fa9c4ca5d33440c82/uvicorn/_compat.py#L17-L18

It's not 100% clear to me right now whether this is an issue with pydevd (or tweaks made to it by PyCharm) or something that needs to be fixed on Uvicorn's end, but I'm apparently not the first person to encounter this. This has also been raised recently as awslabs/amazon-bedrock-agentcore-samples#416.

Kludex avatar Oct 21 '25 19:10 Kludex

@sm-Fifteen you've been involved in the community for long enough, you don't need to create discussions. 🙏


This doesn't seem to be a Uvicorn issue, but I would need to investigate.

Kludex avatar Oct 21 '25 19:10 Kludex

@sm-Fifteen you've been involved in the community for long enough, you don't need to create discussions. 🙏

This doesn't seem to be a Uvicorn issue, but I would need to investigate.

Heh, thanks, but it's been a while, and I wasn't sure if it was right to file this as a uvicorn issue specifically, so I figured I'd do it more by-the-book.

Following the links on the other issue seems to bring up something about nest_asyncio being deprecated, but that library is not coming up in my site-packages or my lockfiles. The error message mentionning a _patch_asyncio.<locals>.run() do seem to indicate that this is what is raising the error, though.

sm-Fifteen avatar Oct 21 '25 19:10 sm-Fifteen

Right, ok, the issue wouldn't have cropped up before v0.36 (specifically #2435) introduced loop_factory to uvicorn.run(). That explains why I didn't run into that error until now.

sm-Fifteen avatar Oct 21 '25 19:10 sm-Fifteen

Hmmm... I can potentially merge #2738 to help, but it doesn't feel right.

Is there something on the PyCharm issue tracker?

Kludex avatar Oct 21 '25 19:10 Kludex

I've found https://youtrack.jetbrains.com/projects/PY/issues/PY-75429/Python-3.12-cannot-debug-asyncio-code, and partially related https://youtrack.jetbrains.com/projects/PY/issues/PY-71488/Cannot-debug-asyncio.Task-with-eagerstart-argument . The JetBrains tracker has proved to be very slow moving for me in the past, though, so I don't know that holding our breath until they fix it on their end would be for the best. On one hand, it would put pressure on them to fix the issue, but it would also leave some users of uvicorn unable to use it.

Case in point, both have been quiet for a month now, with no sign of activity on JetBrains' end.

sm-Fifteen avatar Oct 21 '25 19:10 sm-Fifteen

Actually, nevermind, I didn't read the comments for that second one. There's a workaround pointed out by another Uvicorn user in the comments at the end of that second one:

Workaround by @Anton Mazeev works: Help | Find Actions | Registry, disable python.debug.asyncio.repl

sm-Fifteen avatar Oct 21 '25 19:10 sm-Fifteen

@Kludex: Can confirm, turning off python.debug.asyncio.repl ("Possibility to write await outside of function") eliminates the issue with Uvicorn 0.38.0.

sm-Fifteen avatar Oct 21 '25 20:10 sm-Fifteen

@Kludex: Can confirm, turning off python.debug.asyncio.repl ("Possibility to write await outside of function") eliminates the issue with Uvicorn 0.38.0.

So all good here? (I would like to keep the issue open for visibility anyway)

Kludex avatar Oct 21 '25 20:10 Kludex

@Kludex: I'm wondering if logging a warning or a more detailled error like you were planning to do in #2738 might not be a bad idea, in case that problem ends up lingering for a while longer. The issue I was pointing worards in my original post was from an AWS tool that relied on Uvicorn, so it could affect people who had ni idea whey were using uvicorn, possibly.

As for whether to just log an error and carry on or do a raise-from and crash immediately, I'm not sure.

sm-Fifteen avatar Oct 21 '25 20:10 sm-Fifteen

@Kludex Hi, I'm using Google ADK and that's why our project is affected of this bug, too. I investigated a little bit. You are most probably right, your code is not the cause of this problem. I suspect Pydevd, too. But - You might be able to fix it for many affected people. Though your code does the proper thing in the section you mentioned, the result is not as expected: `if sys.version_info >= (3, 12): asyncio_run = asyncio.run elif sys.version_info >= (3, 11):

def asyncio_run(
    main: Coroutine[Any, Any, _T],
    *,
    debug: bool = False,
    loop_factory: Callable[[], asyncio.AbstractEventLoop] | None = None,
)  ...`

My suggestion: remove the first if-case: if sys.version_info >= (3, 12): asyncio_run = asyncio.run elif

For me, this results in the expected behavior (again). I don't want to discuss pros or cons of this approach here; this leads maybe to a discussion that will result in more discussion. Just want to say what worked for me so far.

nobites avatar Oct 22 '25 09:10 nobites

I'm not doing that. That conditional is a clear path to drop the whole file after 3.12.


I think PyCharm should fork nest_asyncio, or stop using it.

Kludex avatar Oct 22 '25 09:10 Kludex

Maybe you could use inspect.getmodule(asyncio.run) to determine whether asyncio.run() is the real one or an injected copy, and raise a warning if it's not the stock version? Or maybe specifically if it's the pydevd version (like asyncio.run.__module__ == "pydevd_nest_asyncio"), saying it's known to cause errors?

sm-Fifteen avatar Oct 22 '25 17:10 sm-Fifteen