From 4fb1f9a2a77424b7283eb632712466beec7dffc8 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 19 May 2026 10:47:29 +0200 Subject: [PATCH 1/3] fix(strawberry): Fix AttributeError on graphql_span in resolve Strawberry's MiddlewareManager is cached on the schema, so resolve() runs on stale extension instances from the first request. Use sentry_sdk.start_span() instead of self.graphql_span.start_child() so resolve spans parent correctly via the scope rather than relying on instance state. Also prepend (rather than append) the Sentry extension so it wraps all other extensions as the outermost layer. Co-Authored-By: Claude Opus 4.6 --- sentry_sdk/integrations/strawberry.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sentry_sdk/integrations/strawberry.py b/sentry_sdk/integrations/strawberry.py index c962206183..7db086d709 100644 --- a/sentry_sdk/integrations/strawberry.py +++ b/sentry_sdk/integrations/strawberry.py @@ -119,9 +119,9 @@ def _sentry_patched_schema_init( ] # add our extension - extensions.append( + extensions = [ SentryAsyncExtension if should_use_async_extension else SentrySyncExtension - ) + ] + extensions kwargs["extensions"] = extensions @@ -263,7 +263,7 @@ async def resolve( field_path = "{}.{}".format(info.parent_type, info.field_name) - with self.graphql_span.start_child( + with sentry_sdk.start_span( op=OP.GRAPHQL_RESOLVE, name="resolving {}".format(field_path), origin=StrawberryIntegration.origin, @@ -290,7 +290,7 @@ def resolve( field_path = "{}.{}".format(info.parent_type, info.field_name) - with self.graphql_span.start_child( + with sentry_sdk.start_span( op=OP.GRAPHQL_RESOLVE, name="resolving {}".format(field_path), origin=StrawberryIntegration.origin, From 744437238a4830407487a22bee0d8a0c34c37a3b Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 19 May 2026 10:49:01 +0200 Subject: [PATCH 2/3] remove all start_child --- sentry_sdk/integrations/strawberry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/strawberry.py b/sentry_sdk/integrations/strawberry.py index 7db086d709..0ae30b2491 100644 --- a/sentry_sdk/integrations/strawberry.py +++ b/sentry_sdk/integrations/strawberry.py @@ -207,7 +207,7 @@ def on_operation(self) -> "Generator[None, None, None]": self.graphql_span.__exit__(None, None, None) def on_validate(self) -> "Generator[None, None, None]": - self.validation_span = self.graphql_span.start_child( + self.validation_span = sentry_sdk.start_span( op=OP.GRAPHQL_VALIDATE, name="validation", origin=StrawberryIntegration.origin, @@ -218,7 +218,7 @@ def on_validate(self) -> "Generator[None, None, None]": self.validation_span.finish() def on_parse(self) -> "Generator[None, None, None]": - self.parsing_span = self.graphql_span.start_child( + self.parsing_span = sentry_sdk.start_span( op=OP.GRAPHQL_PARSE, name="parsing", origin=StrawberryIntegration.origin, From a9571874e5434e9e28a4943eca7b2cbde98f8108 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 19 May 2026 11:37:50 +0200 Subject: [PATCH 3/3] remove all instance vars --- sentry_sdk/integrations/strawberry.py | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sentry_sdk/integrations/strawberry.py b/sentry_sdk/integrations/strawberry.py index 0ae30b2491..6884190fd6 100644 --- a/sentry_sdk/integrations/strawberry.py +++ b/sentry_sdk/integrations/strawberry.py @@ -152,7 +152,7 @@ def hash_query(self, query: str) -> str: return hashlib.md5(query.encode("utf-8")).hexdigest() def on_operation(self) -> "Generator[None, None, None]": - self._operation_name = self.execution_context.operation_name + operation_name = self.execution_context.operation_name operation_type = "query" op = OP.GRAPHQL_QUERY @@ -168,13 +168,13 @@ def on_operation(self) -> "Generator[None, None, None]": op = OP.GRAPHQL_SUBSCRIPTION description = operation_type - if self._operation_name: - description += " {}".format(self._operation_name) + if operation_name: + description += " {}".format(operation_name) sentry_sdk.add_breadcrumb( category="graphql.operation", data={ - "operation_name": self._operation_name, + "operation_name": operation_name, "operation_type": operation_type, }, ) @@ -183,31 +183,31 @@ def on_operation(self) -> "Generator[None, None, None]": event_processor = _make_request_event_processor(self.execution_context) scope.add_event_processor(event_processor) - self.graphql_span = sentry_sdk.start_span( + graphql_span = sentry_sdk.start_span( op=op, name=description, origin=StrawberryIntegration.origin, ) - self.graphql_span.__enter__() + graphql_span.__enter__() - self.graphql_span.set_data("graphql.operation.type", operation_type) - self.graphql_span.set_data("graphql.operation.name", self._operation_name) + graphql_span.set_data("graphql.operation.type", operation_type) + graphql_span.set_data("graphql.operation.name", operation_name) if should_send_default_pii(): - self.graphql_span.set_data("graphql.document", self.execution_context.query) - self.graphql_span.set_data("graphql.resource_name", self._resource_name) + graphql_span.set_data("graphql.document", self.execution_context.query) + graphql_span.set_data("graphql.resource_name", self._resource_name) yield - transaction = self.graphql_span.containing_transaction + transaction = graphql_span.containing_transaction if transaction and self.execution_context.operation_name: transaction.name = self.execution_context.operation_name transaction.source = TransactionSource.COMPONENT transaction.op = op - self.graphql_span.__exit__(None, None, None) + graphql_span.__exit__(None, None, None) def on_validate(self) -> "Generator[None, None, None]": - self.validation_span = sentry_sdk.start_span( + validation_span = sentry_sdk.start_span( op=OP.GRAPHQL_VALIDATE, name="validation", origin=StrawberryIntegration.origin, @@ -215,10 +215,10 @@ def on_validate(self) -> "Generator[None, None, None]": yield - self.validation_span.finish() + validation_span.finish() def on_parse(self) -> "Generator[None, None, None]": - self.parsing_span = sentry_sdk.start_span( + parsing_span = sentry_sdk.start_span( op=OP.GRAPHQL_PARSE, name="parsing", origin=StrawberryIntegration.origin, @@ -226,7 +226,7 @@ def on_parse(self) -> "Generator[None, None, None]": yield - self.parsing_span.finish() + parsing_span.finish() def should_skip_tracing( self,