strawberry icon indicating copy to clipboard operation
strawberry copied to clipboard

__typename in subscription results in `TypeError: Subscription field must return AsyncIterable. Received: None`

Open kristjanvalur opened this issue 2 years ago • 5 comments

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.

kristjanvalur avatar Jan 26 '22 18:01 kristjanvalur

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!

patrick91 avatar Jan 26 '22 21:01 patrick91

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.

kristjanvalur avatar Jan 27 '22 09:01 kristjanvalur

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 :)

DoctorJohn avatar Feb 01 '22 02:02 DoctorJohn

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: image

I'm using

[[package]]
name = "strawberry-graphql"
version = "0.95.1"

kristjanvalur avatar Feb 01 '22 11:02 kristjanvalur

title -> 'Subscription example error: "Subscription field must return AsyncIterable"'?

jb747 avatar Aug 26 '22 02:08 jb747