strawberry
strawberry copied to clipboard
__typename in subscription results in `TypeError: Subscription field must return AsyncIterable. Received: None`
This has caused me half a day of head scratching. The default subscription query, as provided by the explorer in GraphiQL will create something like
subscription MySubscription {
__typename
count
}
When executed, it results in the server repeatedly failing.
[2022-01-26 18:07:51]: No operation name
subscription MySubscription {
__typename
count
}
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\uvicorn\protocols\websockets\websockets_impl.py", line 190, in run_asgi
result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 75, in __call__
return await self.app(scope, receive, send)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\starlette\applications.py", line 112, in __call__
await self.middleware_stack(scope, receive, send)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\starlette\middleware\errors.py", line 146, in __call__
await self.app(scope, receive, send)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\starlette\middleware\cors.py", line 76,
in __call__
await self.app(scope, receive, send)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\starlette\exceptions.py", line 58, in __call__
await self.app(scope, receive, send)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\starlette\routing.py", line 656, in __call__
await route.handle(scope, receive, send)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\starlette\routing.py", line 315, in handle
await self.app(scope, receive, send)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\strawberry\asgi\__init__.py", line 68, in __call__
await self.graphql_ws_handler_class(
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\strawberry\subscriptions\protocols\graphql_ws\handlers.py", line 66, in handle
return await self.handle_request()
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\strawberry\asgi\handlers\graphql_ws_handler.py", line 52, in handle_request
await self.handle_message(message)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\strawberry\subscriptions\protocols\graphql_ws\handlers.py", line 79, in handle_message
await self.handle_start(message)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\strawberry\subscriptions\protocols\graphql_ws\handlers.py", line 108, in handle_start
result_source = await self.schema.subscribe(
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\strawberry\schema\schema.py", line 194,
in subscribe
return await subscribe(
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\graphql\subscription\subscribe.py", line 58, in subscribe
result_or_stream = await create_source_event_stream(
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\graphql\subscription\subscribe.py", line 147, in create_source_event_stream
return await execute_subscription(context)
File "C:\Users\kristjan\AppData\Local\pypoetry\Cache\virtualenvs\graphql-test-FOqRLQSY-py3.9\lib\site-packages\graphql\subscription\subscribe.py", line 194, in execute_subscription
raise TypeError(
TypeError: Subscription field must return AsyncIterable. Received: None.
interesting! I wonder if this is a bug in graphql-core or in strawberry. I'll mark this as a bug anyway, thanks for reporting it!
My superficial debugging attempt with print statements inside subscription.py revealed that the code:
# Call the `subscribe()` resolver or the default resolver to produce an
# AsyncIterable yielding raw payloads.
resolve_fn = field_def.subscribe or context.field_resolver
print(field_def.subscribe, context.field_resolver)
inside grapql/.../subscribe.py
results in resolve_fn
beging assigned context.field_resolver
, which is a function returning None
.
Didn't dig deeper.
When I attempt to run subscription MySubscription { __typename count}
with graphiql it complains Subscription "MySubscription" must select only one top level field
. This graphql.js validation rule confirms that only one field may be selected.
However, running subscription MySubscription { __typename }
yields the reported TypeError
. I'm pretty sure thats a graphql-core thing which makes sense, since why would you select __typename
if you can only subscribe to one top level field. I'll investigate further though :)
Just verified the behaviour. Using the following code from the docs:
@strawberry.type
class Subscription:
@strawberry.subscription
async def count(self, target: int = 100) -> int:
for i in range(target):
yield i
await asyncio.sleep(0.5)
Gives this here interaction in GraphiQL, which triggers the issue:
I'm using
[[package]]
name = "strawberry-graphql"
version = "0.95.1"
title -> 'Subscription example error: "Subscription field must return AsyncIterable"'?