AttributeError: 'NoneType' object has no attribute '__aenter__' when using asyncio.gather
Hello,
i am using the OnBehalfOf-Flow to fetch informations about applications from graphapi.
When using asyncio.gather to "parallelize" multiple requests (e.g. to fetch application infos and application owners) i get this error AttributeError: 'NoneType' object has no attribute '__aenter__.
This is a minimal example the reproduce the error:
async def main():
scopes = ["https://graph.microsoft.com/Application.ReadWrite.All"]
credentials = OnBehalfOfCredential(
tenant_id=<redacted>,
client_id=<redacted>,
client_secret=<redacted>,
user_assertion=<redacted>,
)
client = GraphServiceClient(credentials=credentials, scopes=scopes)
app, app_owners = await asyncio.gather(*[
client.applications.by_application_id<redacted>).get(),
client.applications.by_application_id(<redacted>).owners.get()
])
asyncio.run(main())
When running those two requests sequentially they work without any problems. So i think there is some sort of race condition going on?
For a large amount of requests, this can have quite a performance impact, because it limits the benefits of actually it runnung concurrently.
Maybe there is an easy fix for it, that i might have overlooked. (E.g. manually trigger token exchange before the asyncio.gather call)
The issue might be related to this other discussion: https://github.com/Azure/azure-sdk-for-python/issues/32309. We get the same error but we're not using asyncio.gather.
I have the same problem, but with ClientSecretCredential
Same here with ClientSecretCredential using it in an AsyncAPIView with django rest framework.
Same Issue here
Same Issue here
[2024-03-15T13:02:17.411Z] ClientSecretCredential.get_token failed: 'NoneType' object has no attribute '__aenter__'
This does not only happen when asyncio.gather is used. I make my msgraph api requests by using aiohttp's background tasks, but this also happens.
I found a workaround: use sync version instead async version. For example, using from azure.identity import ClientSecretCredential instead from azure.identity.aio import ClientSecretCredential
I got the same error in an async with asyncio.TaskGroup() as tg: block.
I solved this error by defining GraphServiceClient in the function that I give to tg.create_task().
tasks = []
async with asyncio.TaskGroup() as tg:
for data in temp:
task = tg.create_task(foo(data))
tasks.append(task)
return [task.result() for task in tasks]
async def foo(data):
credentials = ClientSecretCredential(
tenant_id=... ,
client_id=... ,
client_secret=...
)
scopes = ['https://graph.microsoft.com/.default']
graph_client = GraphServiceClient(credentials, scopes)
return await <GRAPH API ENDPOINT>
This solved for me:
changed this from azure.identity.aio import ClientSecretCredential
to from azure.identity import ClientSecretCredential
The synchronous version of ClientSecretCredential is not being a problem.
I'm using this SDK in Azure Durable Functions. I also get this error and it seems more likely to see it the more requests are being made in a certain time period.
I confirm I have the same issue in Azure (Durable) Functions. I'm using ClientSecretCredential from azure.identity.aio. It always happens after an inactivity period.
I have the same issue even in local from azure.identity import ClientSecretCredential worked for me. What are the consequences of using the synchronous version of ClientSecretCredential?
What are the consequences of using the synchronous version of
ClientSecretCredential?
It may block some parts of the execution. But in my experience with asyncio, multiprocessing, and threading, the GIL doesn't make sure the aio improvement doesn't trickle down into faster execution. So it might not be an issue for you here.
Hello @danielniccoli thanks for using the SDK and for raising.
On investigating this, it looks to be an issue with Azure_identity's management of sync and async requests rather that on the Graph SDK.
Closing this and moving the workarounds to discussion forums to help anyone who experiences this in the future.