Skip to content

Strawberry integration crashes if no query is in request #2715

Closed
@jthorniley

Description

@jthorniley

How do you use Sentry?

Sentry Saas (sentry.io)

Version

1.40.2

Steps to Reproduce

Running an app with the StrawberryIntegration crashes if graphql endpoint is called with no query field in the input data.

  1. Place the attached litestar app code in app.py and install the requirements (sentry, strawberry graphql and litestar)
  2. Run the local server using litestar run
  3. Call the graphql endpoint using curl -v -X POST -d "{}" -H "Content-Type: application/json" http://localhost:8000/graphql
  4. This causes an exception to be raised, whereas if I comment out the sentry_sdk.init() line in the code, the "expected" result of a 400 Bad Request is returned.
  5. (The additional unwanted effect is that the 500 exception goes to sentry as an error in a production app - this is just a minimal reproduction).

app.py:

import logging

from litestar import Litestar
from litestar.logging import LoggingConfig

import sentry_sdk
from sentry_sdk.integrations.strawberry import StrawberryIntegration

import strawberry
from strawberry.litestar import make_graphql_controller

sentry_sdk.init(integrations=[StrawberryIntegration(async_execution=True)])


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello World"


class Schema(strawberry.Schema):
    async def execute(self, *args, **kwargs):
        try:
            return await super().execute(*args, **kwargs)
        except Exception as e:
            logging.getLogger("root").exception(e)
            raise


schema = Schema(Query)

GraphQLController = make_graphql_controller(schema, path="/graphql", debug=True)

app = Litestar(
    route_handlers=[GraphQLController],
    logging_config=LoggingConfig(
        root={"level": logging.getLevelName(logging.INFO), "handlers": ["console"]},
        formatters={
            "standard": {
                "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
            }
        },
    ),
)

pip freeze:

anyio==4.2.0
certifi==2024.2.2
click==8.1.7
EditorConfig==0.12.3
Faker==23.0.0
fast-query-parsers==1.0.3
graphql-core==3.2.3
h11==0.14.0
httpcore==1.0.2
httptools==0.6.1
httpx==0.26.0
idna==3.6
Jinja2==3.1.3
jsbeautifier==1.14.11
litestar==2.6.0
markdown-it-py==3.0.0
MarkupSafe==2.1.5
mdurl==0.1.2
msgspec==0.18.6
multidict==6.0.5
polyfactory==2.14.1
Pygments==2.17.2
python-dateutil==2.8.2
python-dotenv==1.0.1
PyYAML==6.0.1
rich==13.7.0
rich-click==1.7.3
sentry-sdk==1.40.2
six==1.16.0
sniffio==1.3.0
strawberry-graphql==0.219.1
typing_extensions==4.9.0
urllib3==2.2.0
uvicorn==0.27.0.post1
uvloop==0.19.0
watchfiles==0.21.0
websockets==12.0

Expected Result

< HTTP/1.1 400 Bad Request
< date: Wed, 07 Feb 2024 13:52:14 GMT
< server: uvicorn
< content-type: text/plain; charset=utf-8
< content-length: 37
< 
* Connection #0 to host localhost left intact
No GraphQL query found in the request⏎    

Actual Result

< HTTP/1.1 500 Internal Server Error
< date: Wed, 07 Feb 2024 13:53:11 GMT
< server: uvicorn
< content-type: application/json
< content-length: 52
< 
* Connection #0 to host localhost left intact
{"status_code":500,"detail":"Internal Server Error"}⏎ 

On the server console, there is a traceback from inside the strawberry integration:

2024-02-07 13:53:11,970 - root - ERROR - 'NoneType' object has no attribute 'strip'
Traceback (most recent call last):
  File "/Users/james/repos/sentrystrawberry/app.py", line 25, in execute
    return await super().execute(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/james/.pyenv/versions/3.12.0/envs/mixcloud/lib/python3.12/site-packages/strawberry/schema/schema.py", line 263, in execute
    result = await execute(
             ^^^^^^^^^^^^^^
  File "/Users/james/.pyenv/versions/3.12.0/envs/mixcloud/lib/python3.12/site-packages/sentry_sdk/integrations/strawberry.py", line 266, in _sentry_patched_execute_async
    result = await old_execute_async(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/james/.pyenv/versions/3.12.0/envs/mixcloud/lib/python3.12/site-packages/strawberry/schema/execute.py", line 91, in execute
    async with extensions_runner.operation():
  File "/Users/james/.pyenv/versions/3.12.0/envs/mixcloud/lib/python3.12/site-packages/strawberry/extensions/context.py", line 191, in __aenter__
    await self.run_hooks_async()
  File "/Users/james/.pyenv/versions/3.12.0/envs/mixcloud/lib/python3.12/site-packages/strawberry/extensions/context.py", line 177, in run_hooks_async
    hook.initialized_hook.__next__()  # type: ignore[union-attr]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/james/.pyenv/versions/3.12.0/envs/mixcloud/lib/python3.12/site-packages/sentry_sdk/integrations/strawberry.py", line 148, in on_operation
    if self.execution_context.query.strip().startswith("mutation"):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'strip'

Metadata

Metadata

Assignees

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions