Skip to content

Commit 7a3781a

Browse files
sentrivanaclaude
andauthored
fix(strawberry): Fix AttributeError on graphql_span in resolve (getsentry#6289)
Strawberry's `MiddlewareManager` is cached on the schema, so `resolve()` runs on stale extension instances from the first request. Use `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 and captures the whole request. Also make all instance variables that are only used in one method local. ### Description <!-- What changed and why? --> #### Issues - Closes getsentry#4991 - Closes https://linear.app/getsentry/issue/PY-1919/strawberry-uncaught-exception #### Reminders - Please add tests to validate your changes, and lint your code using `tox -e linters`. - Add GH Issue ID _&_ Linear ID (if applicable) - PR title should use [conventional commit](https://develop.sentry.dev/engineering-practices/commit-messages/#type) style (`feat:`, `fix:`, `ref:`, `meta:`) - For external contributors: [CONTRIBUTING.md](https://github.com/getsentry/sentry-python/blob/master/CONTRIBUTING.md), [Sentry SDK development docs](https://develop.sentry.dev/sdk/), [Discord community](https://discord.gg/Ww9hbqr) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3d9c131 commit 7a3781a

1 file changed

Lines changed: 20 additions & 20 deletions

File tree

sentry_sdk/integrations/strawberry.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ def _sentry_patched_schema_init(
119119
]
120120

121121
# add our extension
122-
extensions.append(
122+
extensions = [
123123
SentryAsyncExtension if should_use_async_extension else SentrySyncExtension
124-
)
124+
] + extensions
125125

126126
kwargs["extensions"] = extensions
127127

@@ -152,7 +152,7 @@ def hash_query(self, query: str) -> str:
152152
return hashlib.md5(query.encode("utf-8")).hexdigest()
153153

154154
def on_operation(self) -> "Generator[None, None, None]":
155-
self._operation_name = self.execution_context.operation_name
155+
operation_name = self.execution_context.operation_name
156156

157157
operation_type = "query"
158158
op = OP.GRAPHQL_QUERY
@@ -168,13 +168,13 @@ def on_operation(self) -> "Generator[None, None, None]":
168168
op = OP.GRAPHQL_SUBSCRIPTION
169169

170170
description = operation_type
171-
if self._operation_name:
172-
description += " {}".format(self._operation_name)
171+
if operation_name:
172+
description += " {}".format(operation_name)
173173

174174
sentry_sdk.add_breadcrumb(
175175
category="graphql.operation",
176176
data={
177-
"operation_name": self._operation_name,
177+
"operation_name": operation_name,
178178
"operation_type": operation_type,
179179
},
180180
)
@@ -183,50 +183,50 @@ def on_operation(self) -> "Generator[None, None, None]":
183183
event_processor = _make_request_event_processor(self.execution_context)
184184
scope.add_event_processor(event_processor)
185185

186-
self.graphql_span = sentry_sdk.start_span(
186+
graphql_span = sentry_sdk.start_span(
187187
op=op,
188188
name=description,
189189
origin=StrawberryIntegration.origin,
190190
)
191-
self.graphql_span.__enter__()
191+
graphql_span.__enter__()
192192

193-
self.graphql_span.set_data("graphql.operation.type", operation_type)
194-
self.graphql_span.set_data("graphql.operation.name", self._operation_name)
193+
graphql_span.set_data("graphql.operation.type", operation_type)
194+
graphql_span.set_data("graphql.operation.name", operation_name)
195195
if should_send_default_pii():
196-
self.graphql_span.set_data("graphql.document", self.execution_context.query)
197-
self.graphql_span.set_data("graphql.resource_name", self._resource_name)
196+
graphql_span.set_data("graphql.document", self.execution_context.query)
197+
graphql_span.set_data("graphql.resource_name", self._resource_name)
198198

199199
yield
200200

201-
transaction = self.graphql_span.containing_transaction
201+
transaction = graphql_span.containing_transaction
202202
if transaction and self.execution_context.operation_name:
203203
transaction.name = self.execution_context.operation_name
204204
transaction.source = TransactionSource.COMPONENT
205205
transaction.op = op
206206

207-
self.graphql_span.__exit__(None, None, None)
207+
graphql_span.__exit__(None, None, None)
208208

209209
def on_validate(self) -> "Generator[None, None, None]":
210-
self.validation_span = self.graphql_span.start_child(
210+
validation_span = sentry_sdk.start_span(
211211
op=OP.GRAPHQL_VALIDATE,
212212
name="validation",
213213
origin=StrawberryIntegration.origin,
214214
)
215215

216216
yield
217217

218-
self.validation_span.finish()
218+
validation_span.finish()
219219

220220
def on_parse(self) -> "Generator[None, None, None]":
221-
self.parsing_span = self.graphql_span.start_child(
221+
parsing_span = sentry_sdk.start_span(
222222
op=OP.GRAPHQL_PARSE,
223223
name="parsing",
224224
origin=StrawberryIntegration.origin,
225225
)
226226

227227
yield
228228

229-
self.parsing_span.finish()
229+
parsing_span.finish()
230230

231231
def should_skip_tracing(
232232
self,
@@ -263,7 +263,7 @@ async def resolve(
263263

264264
field_path = "{}.{}".format(info.parent_type, info.field_name)
265265

266-
with self.graphql_span.start_child(
266+
with sentry_sdk.start_span(
267267
op=OP.GRAPHQL_RESOLVE,
268268
name="resolving {}".format(field_path),
269269
origin=StrawberryIntegration.origin,
@@ -290,7 +290,7 @@ def resolve(
290290

291291
field_path = "{}.{}".format(info.parent_type, info.field_name)
292292

293-
with self.graphql_span.start_child(
293+
with sentry_sdk.start_span(
294294
op=OP.GRAPHQL_RESOLVE,
295295
name="resolving {}".format(field_path),
296296
origin=StrawberryIntegration.origin,

0 commit comments

Comments
 (0)