-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RuntimeError: await wasn't used with future #7117
Comments
No idea, but I can give a couple of suggestions for improvements, which may be unrelated.
After I guess trying it on the same Python version might also help reproduce the problem, and maybe using |
Could also just be some weird bug with proactor event loop. The actual line of code that appears to be triggering the error is: I'm not sure how that can possibly be wrong, unless someone is passing in a custom proactor to the event loop with a non-async |
Isn't the outcome of it the same though? Per documentation,
Why is that? If
I'm using whatever comes in stock in Windows. PyInstaller should just freeze the existing code. To me, none of this makes any sense either. My suspicion was that it has to do with internet connection instability, or something like the network interface becoming unavailable / broken for a short moment, but it's just pure guessing, really. Also as a general FYI, the I have no idea what's happening here, but the error sounds like there's a return statement somewhere down the chain of calls, that doesn't return a future, in some quirky edge case I happened to make my code run into. |
Well, if you're sure you need that behaviour, maybe it's fine, I've not seen the rest of the code. But, it's typically discouraged and not needed for most applications.
Right, that's not too obvious from the code, and is not going to be verifiable with mypy. You could just add an assert not None to convince mypy that there is no
Yep, still seems odd. I'd try and test without PyInstaller, just to be sure. But, as you say, it shouldn't matter. |
May be worth filing a bug with cpython as well, I don't see anything here that should result in that. |
I have same error message but for |
Can this issue #81353 relate to this? |
Okey, if I remove |
One of my application's users was able to get a reliable repro on Linux, by intentionally breaking the SSL certificates filepath. Doing so results in this exact, non-descriptive error. Ref: DevilXD/TwitchDropsMiner#80 (comment) There's also a more extensive explanation of the find here: DevilXD/TwitchDropsMiner#113 (comment) Please note that this original issue comes from Windows, but these clearly show that if something goes wrong on the system side of things, one might end up with this exact, confusing error. The question is, is this an issue with |
I think it needs a cpython bug. If you want to try and dig further, and you can convince them to hack their Python install, it appears that error comes from the Future itself (which makes the error seem a little misleading): So, I'm guessing that when the loop yields from the Future, for some reason it ends up resuming the future before it has actually finished, which should never happen. Unfortunately, I've not found any further information on why that check exists as it has been there since asyncio was introduced 10 years ago. But, I'm pretty lost at this point on how exactly the future gets to that point, or what an SSL error should have to do with it. |
@Dreamsorcerer I did the same investigation. ) In my case, Twisted somehow breaks it, but the behavior is the same. I need extra few days to figure out. |
okey, it's happened if you back to |
@stalkerg You seem to understand what's happening. Mind leaving a more in-depth explanation here? Where is the source of the error, in asyncio or aiohttp? |
@DevilXD In my case, it was what twisted fromCoroutine doesn't support asyncio. In your case, I think you can't use The main idea of this issue - we found what future is not done, we do |
I think that's fine (and works in a trivial example). Certainly seems to be something to do with Windows/Proactor though. Did we manage to test without PyInstaller? Looking back at that traceback, to me it doesn't look like it matches the cpython source code properly, so I'm not sure it's actually using the exact same code as a normal Python install... |
There is a "supposedly 100% working" repro explanation for Linux available here: DevilXD/TwitchDropsMiner#80 (comment) I've tried testing this on Windows, by setting the same env var via |
Feel free to provide some more information on how to test. I ran that application with that command, getting the GUI open, but didn't get any errors. If it requires some user credentials or something, feel free to email me privately with testing details. |
It's probably because it's been a while since it happened, and this issue got worked around. As far as I can recall, the finder of the repro ran into the error by accident, while trying to add Linux support to the TDM project. This commit was the result: DevilXD/TwitchDropsMiner@e31dcd8 I'm not a linux person, but the commit includes some lenghty explanation to it. I'm assuming that commenting out the import and SSL injection lines will make it happen again? If that won't do, we can ask the repro finder to retrace their steps from back then, I guess. |
Still no error on starting the app. |
it's 100% not a ssl issue.
this is the case, as I saw my issue |
I don't think anybody claimed it was. It's just that messing with SSL seems to be a way to reproduce the issue in the given app.
I think what you were looking at in Twisted is code that was handling event loop logic, whereas this is high-level application logic. This code merely |
@guihkx Would it be possible for you to recreate the repro from here?: DevilXD/TwitchDropsMiner#80 (comment) I know things have changed since then, but it'd be helpful here. Removing the If you would somehow still reproduce it, I guess it'd be good to know what system it happens on. The DevilXD/TwitchDropsMiner@e31dcd8 commit mentions several different Linux systems, so I'd imagine it works on some, while breaks on the others. |
@DevilXD Still reproducible for me on Also, in addition to pointing I'm not sure why that is, but due to the bleeding-edge nature of Arch Linux, system packages tend to be updated to their latest version as soon as possible, and both
But like I mentioned in my other post, I'm not sure what intentionally breaking libssl has anything to do with this bug, especially when it also happens on Python for Windows, which doesn't rely on libssl, AFAIK. If it helps, here's the latest stack trace of that error at DevilXD/TwitchDropsMiner@562627e: Click me to expand
You don't have to be logged in to Twitch and it happens instantly too, as soon as the GUI loads. Let me know if I can provide any other useful information. |
Thanks, reproduced with |
No idea: python/cpython#106429 |
If sleep also shows such an error, it means something (SSL?) is blocking/interrupt the event loop. And yes, we need a smaller repro. |
Yes, exactly what I was about to say. I suspect we'll struggle to figure out anything more unless someone can start cutting down the code to find the minimum amount of code that reproduces the error. |
If you can't test on a Linux machine for some reason, then I'd suggest setting the env vars to an empty file (/dev/null is a valid file path on Linux) to see if that reproduces. There is also a Linux subsystem for Windows or something, which should allow you to run the app in a Linux-like environment with the same arguments. If you can reproduce and then break your code down until you get a minimal reproducer, then we can probably figure out what the issue is. It could be something you are doing in the app that is breaking it, but I don't think it's the snippet of code provided earlier. |
Having a glance at the code more widely, I'm not sure I can pick out what is necessarily the issue, but I can see some things that have a small chance of causing problems.
Also, a more robust, cross-platform approach to only run 1 instance (https://github.com/DevilXD/TwitchDropsMiner/blob/master/main.py#L134) is to use a lockfile (e.g. https://bazaar.launchpad.net/~dreamsorcerer/btrfs-backup-suite/trunk/view/head:/btrfs_backup/commands.py#L37) |
I've started with Python 3.6, back when it wasn't very popular to use
As far as I'm aware, tasks are "self-awaitable". As long as the loop is running, a cancelled task will eventually finish running and just get GCed, without having to await on it. Furthermore, the only thing awaiting on it does, is give me the result of it, either whatever it returned, or reraises an exception it raised ( In all places where tasks are getting cancelled, 99.9% of the time, it's the Is there a particular line in my code I should really be awaiting on the cancelled tasks?
Thanks, I'm still kinda new to multi-platform support. Linux support was added not too long ago, hence why that part stayed as-is. I'll look into changing the implementation to use a lock file eventually. Thanks for the tip 🙂 EDIT: I've implemented the |
Is there a possibility of moving this forward by chance? Reliable repro for this has been posted in python/cpython#106429 If I'd need to provide some additional information, or can somehow help in any other way, please let me know. |
Can you put your repro here? Seems like it's a aiohttp bug or around. Maybe even better to create a new fresh issue with small repro and etc. |
The repro is quite complicated, but sure (from the linked issue): import asyncio
import aiohttp
async def main():
async with aiohttp.ClientSession() as session:
try:
response = await asyncio.ensure_future(session.get('https://www.google.com/'))
print(await response.text())
finally:
response.release()
asyncio.run(main()) Env vars needed (intentionally break SSL certs dir path):
More specifics as to where all of this comes from is in the linked issue, specifically here: python/cpython#106429 (comment) The issue itself still appears to manifest itself "randomly" on different machines, running both Windows or Linux. In general, there's 3 cases of it:
Again, this seems to be on a per-machine basis. Extra info EDIT: The linked issue reduces this to |
Okay, so I have some additional information to the issue. I've had a user contact me today, and tell me they've ran into problem (for context, I'm talking about the project I maintain, that is linked in the initial message of this issue). After explaining them the bug is machine-dependent and they've probably did something to their PC recently, they've told me they've "fully reset their pc today". Knowing this possibly has to do with SSL certs store and them most likely being missing on a fresh machine, I've told them to run this as a completely separate script: import asyncio
import aiohttp
async def main():
async with aiohttp.ClientSession() as session:
async with session.get("https://www.google.com") as response:
await response.text()
asyncio.run(main()) ..., and then check if the application works now - and it did. What I imagined may happen, is that this bit will take care of fetching and caching the certs on the machine locally, so that the application code won't have to do it, avoiding the error - and it seems to have worked? All of this happened on Win10. Whatever this bug is related to, it seems to be affected by something Hope this helps in any way. |
Thanks, I can reproduce it! I will try to look into it.
similar for uvloop:
After disabling C implementation for asyncio this issue became more clear. Seems like I can find a reason. |
Okey, I solved it locally. :) But to explain what is it I need a time. It's combination of aiohttp trick + race condition in Python. |
The forbidden knowledge... Take your time. I'm glad this is finally going somewhere. In any case, I'd like to know the real cause behind it, but I'm willing to wait if that's needed of course. |
But the connection with the real issue is very indirect. |
Good to hear, I never managed to reproduce the issue myself. But, still haven't had time to look at it yet (and may have been completely unrelated). |
Okey, I am ready to make PR. It's a one line fix in aiohttp. |
@Dreamsorcerer @DevilXD can you check my bugfix? #7785 |
Verifying it myself will be tricky, considering I've only ran into this issue once, and then never again. Unless you know how to reliably force it to trigger on Windows. I've asked people who experience it to test it, but it'll take some time before someone does so. I'll report once I have some results. |
@DevilXD you can try my repro from the PR |
In that case, then besides adding the missing Traceback (most recent call last):
File "C:\Users\DevilXD\Desktop\test.py", line 67, in <module>
asyncio.run(main())
File "C:\Python38\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Python38\lib\asyncio\base_events.py", line 616, in run_until_complete
return future.result()
File "C:\Users\DevilXD\Desktop\test.py", line 65, in main
await task
File "C:\Users\DevilXD\Desktop\test.py", line 16, in send
return self._coro.send(arg)
File "C:\Users\DevilXD\Desktop\test.py", line 59, in my_task
raise Exception("test")
Exception: test Without the change, the original exception from this issue appears. I don't think this qualifies as a valid library test though. To confirm the PR solves this issue, we need a confirmation from someone who experienced it, then installed your PR fix, and then tested again to see if it stops happening. I'm pretty sure that's really all it takes to fix it, but I'd still like to make sure. Reproducing this on Windows would most likely need removing some cached SSL certs and/or DNS cache, or similar. |
@DevilXD you should just add ipv6 somehow or mock host resolve to return more than one IP. |
@DevilXD please try this import sys
sys.modules['_asyncio'] = None
import asyncio
import aiohttp
import socket
import ssl
async def _resolve_host(self, host, port, traces = None):
return [
{
"host": "142.251.222.4",
"port": 443,
"family": socket.AddressFamily.AF_INET,
"flags": socket.AddressInfo.AI_NUMERICHOST | socket.AddressInfo.AI_NUMERICSERV,
"proto": 6,
"hostname": "www.google.com",
},
{
"host": "142.251.222.4",
"port": 443,
"family": socket.AddressFamily.AF_INET,
"flags": socket.AddressInfo.AI_NUMERICHOST | socket.AddressInfo.AI_NUMERICSERV,
"proto": 6,
"hostname": "www.google.com",
}
]
async def main():
aiohttp.TCPConnector._resolve_host = _resolve_host
async with aiohttp.ClientSession() as session:
response = None
try:
response = await asyncio.ensure_future(session.get('https://www.google.com/'))
print(await response.text())
finally:
if response:
response.release()
asyncio.run(main()) it should cause the error even for you. |
This PR fixes #7117 and similar issues. Short explanation - our coroutine wrapper does not properly handle the exception, which breaks coroutine handling. As you can see, any task expects results from `throw` - https://github.com/python/cpython/blob/main/Lib/asyncio/tasks.py#L303 but it seems like in aiohttp it was acidently removed by this commit stalkerg@f04ecc2#diff-f334e752b4894ef951105572ab8b195aeb8db90eb6e48b1dfbd9a01da4c854f5L842 This is repro a case without aiohttp: ```python import ssl import collections class TestCoroWrapper(collections.abc.Coroutine): __slots__ = ("_coro", "_resp") def __init__(self, coro): self._coro = coro def __getattr__(self, attr): return getattr(self._coro, attr) def send(self, arg): return self._coro.send(arg) def throw(self, arg): self._coro.throw(arg) def close(self): return self._coro.close() def __await__(self): ret = self._coro.__await__() return ret async def ssl_call(context): loop = asyncio.get_event_loop() return await loop.create_connection( lambda: asyncio.Protocol(), '2404:6800:4004:824::2004', 443, ssl=context, family=socket.AddressFamily.AF_INET6, proto=6, flags=socket.AddressInfo.AI_NUMERICHOST | socket.AddressInfo.AI_NUMERICSERV, server_hostname='www.google.com', local_addr=None ) async def prepare_call(): context = ssl.create_default_context() try: connection = await ssl_call(context) except ssl.SSLError as e: print(f"Got exception1: {e}") raise e return connection async def my_task(): try: await prepare_call() except Exception as e: print(f"Got exception2: {e}") await asyncio.sleep(1) raise Exception("test") async def main(): my_coro = TestCoroWrapper(my_task()) print(f"is coro? {asyncio.iscoroutine(my_coro)}") task = asyncio.create_task(my_coro) await task asyncio.run(main()) ``` The `TestCoroWrapper` here is equivalent of `_BaseRequestContextManager`. If you run such code like: `SSL_CERT_FILE=/dev/null SSL_CERT_DIR=/dev/null python test.py` you will get an error: `await wasn't used with future`. The main idea here is that you are trying to await the sleep function after getting and catching an exception from the native (SSL) module. Now I should explain why repro with aiohttp for some users return the same error: ```python import asyncio import aiohttp async def main(): async with aiohttp.ClientSession() as session: try: response = await asyncio.ensure_future(session.get('https://www.google.com/')) print(await response.text()) finally: response.release() asyncio.run(main()) ``` here it's happened because in `TCPConnector._create_direct_connection` we are getting all IPs for the given host and trying to connect one by one. If the first connection gets an error we will catch this error and try again for the next IP. If you have IPv6 you will have at least 2 IPs here (ipv6 and ipv4), and after the first error, you will try to connect to a second IP and get the same error. Why it's problem only for `asyncio.ensure_future`? Because `asyncio.ensure_future` creates a `task` such a task starts processing coroutines and directly communicates with our coroutine wrapper witch not return a result for `throw`. I will write changelog and etc after people validate this PR. But honestly, I don't think I can write a unit test for a such case. Regards, ## Checklist - [ ] I think the code is well written - [ ] Unit tests for the changes exist - [ ] Documentation reflects the changes - [ ] If you provide code modification, please add yourself to `CONTRIBUTORS.txt` * The format is <Name> <Surname>. * Please keep alphabetical order, the file is sorted by names. - [ ] Add a new news fragment into the `CHANGES` folder * name it `<issue_id>.<type>` for example (588.bugfix) * if you don't have an `issue_id` change it to the pr id after creating the pr * ensure type is one of the following: * `.feature`: Signifying a new feature. * `.bugfix`: Signifying a bug fix. * `.doc`: Signifying a documentation improvement. * `.removal`: Signifying a deprecation or removal of public API. * `.misc`: A ticket has been closed, but it is not of interest to users. * Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files." --------- Co-authored-by: Sam Bull <[email protected]> Co-authored-by: Sam Bull <[email protected]>
This PR fixes #7117 and similar issues. Short explanation - our coroutine wrapper does not properly handle the exception, which breaks coroutine handling. As you can see, any task expects results from `throw` - https://github.com/python/cpython/blob/main/Lib/asyncio/tasks.py#L303 but it seems like in aiohttp it was acidently removed by this commit stalkerg@f04ecc2#diff-f334e752b4894ef951105572ab8b195aeb8db90eb6e48b1dfbd9a01da4c854f5L842 This is repro a case without aiohttp: ```python import ssl import collections class TestCoroWrapper(collections.abc.Coroutine): __slots__ = ("_coro", "_resp") def __init__(self, coro): self._coro = coro def __getattr__(self, attr): return getattr(self._coro, attr) def send(self, arg): return self._coro.send(arg) def throw(self, arg): self._coro.throw(arg) def close(self): return self._coro.close() def __await__(self): ret = self._coro.__await__() return ret async def ssl_call(context): loop = asyncio.get_event_loop() return await loop.create_connection( lambda: asyncio.Protocol(), '2404:6800:4004:824::2004', 443, ssl=context, family=socket.AddressFamily.AF_INET6, proto=6, flags=socket.AddressInfo.AI_NUMERICHOST | socket.AddressInfo.AI_NUMERICSERV, server_hostname='www.google.com', local_addr=None ) async def prepare_call(): context = ssl.create_default_context() try: connection = await ssl_call(context) except ssl.SSLError as e: print(f"Got exception1: {e}") raise e return connection async def my_task(): try: await prepare_call() except Exception as e: print(f"Got exception2: {e}") await asyncio.sleep(1) raise Exception("test") async def main(): my_coro = TestCoroWrapper(my_task()) print(f"is coro? {asyncio.iscoroutine(my_coro)}") task = asyncio.create_task(my_coro) await task asyncio.run(main()) ``` The `TestCoroWrapper` here is equivalent of `_BaseRequestContextManager`. If you run such code like: `SSL_CERT_FILE=/dev/null SSL_CERT_DIR=/dev/null python test.py` you will get an error: `await wasn't used with future`. The main idea here is that you are trying to await the sleep function after getting and catching an exception from the native (SSL) module. Now I should explain why repro with aiohttp for some users return the same error: ```python import asyncio import aiohttp async def main(): async with aiohttp.ClientSession() as session: try: response = await asyncio.ensure_future(session.get('https://www.google.com/')) print(await response.text()) finally: response.release() asyncio.run(main()) ``` here it's happened because in `TCPConnector._create_direct_connection` we are getting all IPs for the given host and trying to connect one by one. If the first connection gets an error we will catch this error and try again for the next IP. If you have IPv6 you will have at least 2 IPs here (ipv6 and ipv4), and after the first error, you will try to connect to a second IP and get the same error. Why it's problem only for `asyncio.ensure_future`? Because `asyncio.ensure_future` creates a `task` such a task starts processing coroutines and directly communicates with our coroutine wrapper witch not return a result for `throw`. I will write changelog and etc after people validate this PR. But honestly, I don't think I can write a unit test for a such case. Regards, - [ ] I think the code is well written - [ ] Unit tests for the changes exist - [ ] Documentation reflects the changes - [ ] If you provide code modification, please add yourself to `CONTRIBUTORS.txt` * The format is <Name> <Surname>. * Please keep alphabetical order, the file is sorted by names. - [ ] Add a new news fragment into the `CHANGES` folder * name it `<issue_id>.<type>` for example (588.bugfix) * if you don't have an `issue_id` change it to the pr id after creating the pr * ensure type is one of the following: * `.feature`: Signifying a new feature. * `.bugfix`: Signifying a bug fix. * `.doc`: Signifying a documentation improvement. * `.removal`: Signifying a deprecation or removal of public API. * `.misc`: A ticket has been closed, but it is not of interest to users. * Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files." --------- Co-authored-by: Sam Bull <[email protected]> Co-authored-by: Sam Bull <[email protected]> (cherry picked from commit a57dc31)
This PR fixes #7117 and similar issues. Short explanation - our coroutine wrapper does not properly handle the exception, which breaks coroutine handling. As you can see, any task expects results from `throw` - https://github.com/python/cpython/blob/main/Lib/asyncio/tasks.py#L303 but it seems like in aiohttp it was acidently removed by this commit stalkerg@f04ecc2#diff-f334e752b4894ef951105572ab8b195aeb8db90eb6e48b1dfbd9a01da4c854f5L842 This is repro a case without aiohttp: ```python import ssl import collections class TestCoroWrapper(collections.abc.Coroutine): __slots__ = ("_coro", "_resp") def __init__(self, coro): self._coro = coro def __getattr__(self, attr): return getattr(self._coro, attr) def send(self, arg): return self._coro.send(arg) def throw(self, arg): self._coro.throw(arg) def close(self): return self._coro.close() def __await__(self): ret = self._coro.__await__() return ret async def ssl_call(context): loop = asyncio.get_event_loop() return await loop.create_connection( lambda: asyncio.Protocol(), '2404:6800:4004:824::2004', 443, ssl=context, family=socket.AddressFamily.AF_INET6, proto=6, flags=socket.AddressInfo.AI_NUMERICHOST | socket.AddressInfo.AI_NUMERICSERV, server_hostname='www.google.com', local_addr=None ) async def prepare_call(): context = ssl.create_default_context() try: connection = await ssl_call(context) except ssl.SSLError as e: print(f"Got exception1: {e}") raise e return connection async def my_task(): try: await prepare_call() except Exception as e: print(f"Got exception2: {e}") await asyncio.sleep(1) raise Exception("test") async def main(): my_coro = TestCoroWrapper(my_task()) print(f"is coro? {asyncio.iscoroutine(my_coro)}") task = asyncio.create_task(my_coro) await task asyncio.run(main()) ``` The `TestCoroWrapper` here is equivalent of `_BaseRequestContextManager`. If you run such code like: `SSL_CERT_FILE=/dev/null SSL_CERT_DIR=/dev/null python test.py` you will get an error: `await wasn't used with future`. The main idea here is that you are trying to await the sleep function after getting and catching an exception from the native (SSL) module. Now I should explain why repro with aiohttp for some users return the same error: ```python import asyncio import aiohttp async def main(): async with aiohttp.ClientSession() as session: try: response = await asyncio.ensure_future(session.get('https://www.google.com/')) print(await response.text()) finally: response.release() asyncio.run(main()) ``` here it's happened because in `TCPConnector._create_direct_connection` we are getting all IPs for the given host and trying to connect one by one. If the first connection gets an error we will catch this error and try again for the next IP. If you have IPv6 you will have at least 2 IPs here (ipv6 and ipv4), and after the first error, you will try to connect to a second IP and get the same error. Why it's problem only for `asyncio.ensure_future`? Because `asyncio.ensure_future` creates a `task` such a task starts processing coroutines and directly communicates with our coroutine wrapper witch not return a result for `throw`. --------- Co-authored-by: Sam Bull <[email protected]> Co-authored-by: Sam Bull <[email protected]> (cherry picked from commit a57dc31) Co-authored-by: Yury Zhuravlev <[email protected]>
…ibs#7786) This PR fixes aio-libs#7117 and similar issues. Short explanation - our coroutine wrapper does not properly handle the exception, which breaks coroutine handling. As you can see, any task expects results from `throw` - https://github.com/python/cpython/blob/main/Lib/asyncio/tasks.py#L303 but it seems like in aiohttp it was acidently removed by this commit stalkerg@f04ecc2#diff-f334e752b4894ef951105572ab8b195aeb8db90eb6e48b1dfbd9a01da4c854f5L842 This is repro a case without aiohttp: ```python import ssl import collections class TestCoroWrapper(collections.abc.Coroutine): __slots__ = ("_coro", "_resp") def __init__(self, coro): self._coro = coro def __getattr__(self, attr): return getattr(self._coro, attr) def send(self, arg): return self._coro.send(arg) def throw(self, arg): self._coro.throw(arg) def close(self): return self._coro.close() def __await__(self): ret = self._coro.__await__() return ret async def ssl_call(context): loop = asyncio.get_event_loop() return await loop.create_connection( lambda: asyncio.Protocol(), '2404:6800:4004:824::2004', 443, ssl=context, family=socket.AddressFamily.AF_INET6, proto=6, flags=socket.AddressInfo.AI_NUMERICHOST | socket.AddressInfo.AI_NUMERICSERV, server_hostname='www.google.com', local_addr=None ) async def prepare_call(): context = ssl.create_default_context() try: connection = await ssl_call(context) except ssl.SSLError as e: print(f"Got exception1: {e}") raise e return connection async def my_task(): try: await prepare_call() except Exception as e: print(f"Got exception2: {e}") await asyncio.sleep(1) raise Exception("test") async def main(): my_coro = TestCoroWrapper(my_task()) print(f"is coro? {asyncio.iscoroutine(my_coro)}") task = asyncio.create_task(my_coro) await task asyncio.run(main()) ``` The `TestCoroWrapper` here is equivalent of `_BaseRequestContextManager`. If you run such code like: `SSL_CERT_FILE=/dev/null SSL_CERT_DIR=/dev/null python test.py` you will get an error: `await wasn't used with future`. The main idea here is that you are trying to await the sleep function after getting and catching an exception from the native (SSL) module. Now I should explain why repro with aiohttp for some users return the same error: ```python import asyncio import aiohttp async def main(): async with aiohttp.ClientSession() as session: try: response = await asyncio.ensure_future(session.get('https://www.google.com/')) print(await response.text()) finally: response.release() asyncio.run(main()) ``` here it's happened because in `TCPConnector._create_direct_connection` we are getting all IPs for the given host and trying to connect one by one. If the first connection gets an error we will catch this error and try again for the next IP. If you have IPv6 you will have at least 2 IPs here (ipv6 and ipv4), and after the first error, you will try to connect to a second IP and get the same error. Why it's problem only for `asyncio.ensure_future`? Because `asyncio.ensure_future` creates a `task` such a task starts processing coroutines and directly communicates with our coroutine wrapper witch not return a result for `throw`. --------- Co-authored-by: Sam Bull <[email protected]> Co-authored-by: Sam Bull <[email protected]> (cherry picked from commit a57dc31) Co-authored-by: Yury Zhuravlev <[email protected]>
Describe the bug
This is a strange one, as it's not something that has ever happened to me, but one of my users reported as an reoccurring issue. There's no real repro steps. It seems like it's something wrong with my code, but I can't pin-point exactly what it is, and the error makes zero sense. I don't know aiohttp or asyncio internals, so I'm making this bug report in hopes of finding out if it's really just my code, or is there something wrong with aiohttp itself.
To Reproduce
No steps as I said, but here are the two functions that are common to both tracebacks, right before it enters aiohttp internals:
Expected behavior
Well, I expect no error.
Logs/tracebacks
Python Version
aiohttp Version
Version: 3.8.3 (both cases)
multidict Version
Version: 6.0.2 (both cases)
yarl Version
Version: 1.8.1 (both cases)
OS
Windows 10 x64 (theirs)
Windows 7 x64 (mine)
Related component
Client
Additional context
The entirety of the source code, for reference, is available here: https://github.com/DevilXD/TwitchDropsMiner
Ref issue: DevilXD/TwitchDropsMiner#80
Code of Conduct
The text was updated successfully, but these errors were encountered: