Skip to content

feat(network-details): Introduce new swizzling to capture response bodies for session replay#7584

Open
43jay wants to merge 4 commits intomobile-935/data-classesfrom
mobile-935/new-swizzling
Open

feat(network-details): Introduce new swizzling to capture response bodies for session replay#7584
43jay wants to merge 4 commits intomobile-935/data-classesfrom
mobile-935/new-swizzling

Conversation

@43jay
Copy link
Copy Markdown
Collaborator

@43jay 43jay commented Mar 3, 2026

📜 Description

  • Newly swizzled methods:
    [NSURLSession dataTaskWithURL:completionHandler:]
    [NSURLSession dataTaskWithRequest:completionHandler:]

  • This swizzling is skipped when network detail capture is not enabled (SentryReplayOptions#networkDetailAllowUrls is empty)

  • Added testing to validate for future iOS SDKs that the IMPs we are swizzling are implemented directly on NSURLSession: SentryNSURLSessionTaskSearchTests

    • test_URLSessionDataTaskWithRequest_ByIosVersion
    • test_URLSessionDataTaskWithURL_ByIosVersion

💡 Motivation and Context

With this change sentry-cocoa can inspect response bodies of NSURLSession dataTask's that use completionHandlers.

Swizzling is added to inspect the NSURLResponse before delegating to the original completionHandler.
The request body will be captured via existing swizzling into SentryNetworkTracker (setState, resume).

See swizzling discussion on #7582 for more context.

💚 How did you test it?

Unit tests

xcodebuild test -workspace Sentry.xcworkspace -scheme Sentry -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -only-testing:Tests/SentryTests/Integrations/Performance/Network/SentryNSURLSessionTaskSearchTests.swift | xcbeautify

test_URLSessionTask_ByIosVersion ✅
test_URLSessionDataTaskWithRequest_ByIosVersion ✅
test_URLSessionDataTaskWithURL_ByIosVersion ✅

SKIP_SWIFTLINT=1 xcodebuild test -workspace Sentry.xcworkspace -scheme Sentry -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -only-testing:SentryTests/SentrySwizzleWrapperHelperTests

make test-ios ONLY_TESTING=SentryNetworkDetailSwizzlingTests 2>&1 | xcbeautify
...
Test Suite 'SentryNetworkDetailSwizzlingTests' started at 2026-04-13 13:55:14.423.
Executed 2 tests, with 0 failures (0 unexpected) in 2.100 (2.100) seconds

📝 Checklist

You have to check all boxes before merging:

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled. gated by networkDetailAllowUrls
  • I updated the docs if needed. future pr
  • I updated the wizard if needed. N/A
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog. #skip-changelog future PR
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs. 🤔

@linear
Copy link
Copy Markdown

linear bot commented Mar 3, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 3, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


This PR will not appear in the changelog.


🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 3, 2026

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against c24784c

@43jay 43jay marked this pull request as ready for review March 3, 2026 20:10
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 3, 2026

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
4607 2 4605 21
View the top 2 failed test(s) by shortest run time
SentryTests.SentryNetworkDetailSwizzlingTests::testDataTaskWithRequest_completionHandler_capturesNetworkDetails
Stack Traces | 0s run time
.../Performance/Network/SentryNetworkDetailSwizzlingTests.swift:77 - XCTUnwrap failed: expected non-nil value of type "SentryReplayNetworkDetails" - Swizzled completion handler should have populated network details on the breadcrumb
SentryTests.SentryNetworkDetailSwizzlingTests::testDataTaskWithURL_completionHandler_capturesNetworkDetails
Stack Traces | 0s run time
.../Performance/Network/SentryNetworkDetailSwizzlingTests.swift:123 - XCTUnwrap failed: expected non-nil value of type "SentryReplayNetworkDetails" - Swizzled completion handler should have populated network details on the breadcrumb

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Copy link
Copy Markdown
Member

@philipphofmann philipphofmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this. I have one major high-level question before reviewing this more closely.

@43jay 43jay force-pushed the mobile-935/data-classes branch from 71fd40b to 78d1d60 Compare March 4, 2026 21:03
@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 9473efb to 5bc5830 Compare March 4, 2026 21:03
@43jay 43jay force-pushed the mobile-935/data-classes branch from 78d1d60 to 9a4f8b3 Compare March 4, 2026 22:00
@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 5bc5830 to 7faf4ef Compare March 4, 2026 22:00
@43jay 43jay force-pushed the mobile-935/data-classes branch from 9a4f8b3 to c62d15c Compare March 6, 2026 16:33
@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 7faf4ef to 6e19c0a Compare March 6, 2026 16:33
@43jay 43jay force-pushed the mobile-935/data-classes branch from c62d15c to e717c1a Compare March 6, 2026 19:25
@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 6e19c0a to 9a8d48d Compare March 6, 2026 19:25
@43jay 43jay marked this pull request as draft March 9, 2026 15:12
@43jay 43jay force-pushed the mobile-935/new-swizzling branch 2 times, most recently from 8584657 to c3afd6d Compare March 9, 2026 19:02
@43jay 43jay force-pushed the mobile-935/data-classes branch 2 times, most recently from 2d31c8d to 72a427a Compare March 9, 2026 19:48
@43jay 43jay force-pushed the mobile-935/new-swizzling branch 2 times, most recently from 6e873ec to a691160 Compare March 9, 2026 20:51
@43jay 43jay force-pushed the mobile-935/data-classes branch from 72a427a to 56c7a59 Compare March 9, 2026 20:51
@43jay 43jay marked this pull request as ready for review March 9, 2026 21:00
@43jay 43jay force-pushed the mobile-935/data-classes branch from 56c7a59 to a41d68f Compare March 10, 2026 21:06
@43jay 43jay force-pushed the mobile-935/new-swizzling branch from a691160 to 7db5474 Compare March 10, 2026 21:06
@philipphofmann
Copy link
Copy Markdown
Member

philipphofmann commented Mar 11, 2026

Review notes — treat with care

Disclaimer: I'm on parental leave starting Monday, so I only gave this a quick glance today. Most of the investigation below came from prompting Claude Code — I walked it through the code step by step, asked it to trace the task usage across the PR stack, and challenged its initial assessment when things felt off. The findings are plausible and worth considering, but I haven't verified everything myself. Treat this as "leads worth investigating" rather than definitive conclusions. If needed, I can take another look tomorrow or the day after, but it might be better if @itaybre or @philprime takes this over fully.


TL;DR — suggested restructure

The taskHolder pattern (mutable array to break a chicken-and-egg dependency between the completion handler and the task) feels fishy. The completion handler doesn't actually need the task if you restructure the flow:

  1. Don't use the task as a bridge between request-time and response-time data
  2. Do all replay network detail processing in the completion handler itself — it already has request (captured in swizzle scope), response, and data
  3. Don't piggyback on the setState:/breadcrumb path — the completion handler fires after setState:, so the timing doesn't work anyway

The completion handler swizzle would become a simple, self-contained block with no tricky patterns:

wrapped = ^(NSData *data, NSURLResponse *response, NSError *error) {
    if (!error && data) {
        [networkTracker captureNetworkDetailsForReplayWithRequest:request
                                                        response:response
                                                    responseData:data];
    }
    completionHandler(data, response, error);
};

No taskHolder, no objc_getAssociatedObject lookup in the completion handler, no timing dependencies.


Detailed findings from Claude Code investigation

1. The taskHolder chicken-and-egg pattern

The wrapped completion handler needs a reference to the NSURLSessionDataTask, but the task doesn't exist yet when the handler is constructed. The current solution:

taskHolder = NSMutableArray (empty)
task = SentrySWCallOriginal(request, wrappedHandler)  // wrappedHandler captures taskHolder
[taskHolder addObject:task]
return task

The assumption is: the completion handler will never fire before [taskHolder addObject:task] because the task starts in NSURLSessionTaskStateSuspended and must be resumed first.

Why this is concerning: This relies on an undocumented implementation detail. Apple doesn't guarantee that:

  • A cached response won't trigger the completion handler synchronously during creation
  • An invalid/malformed request won't deliver an error inline before returning
  • An invalidated session won't call back immediately
  • This behavior won't change in a future OS version

If any of these edge cases fire the completion handler during SentrySWCallOriginal, taskHolder.firstObject is nil, and capture silently fails. No crash, just silent data loss — which is worse because you'd never notice.

2. The setState: vs completion handler timing

I asked Claude to trace the execution order. The setState: swizzle fires before the completion handler:

1. Our setState: swizzle fires (task.state is still .running)
2. Original setState: executes (state becomes .completed)
3. Completion handler fires

This means the approach in #7590 (reading SentryReplayNetworkDetails from the task in addBreadcrumbForSessionTask:) would read the associated object before the completion handler has populated the response data. This is a second potential race condition in the stack.

3. Class cluster concern

The swizzle targets [NSURLSession class], but NSURLSession is a class cluster — actual instances are private subclasses (e.g., __NSURLSessionLocal). If those subclasses override dataTaskWithRequest:completionHandler:, the swizzle on the base class won't intercept the calls. Compare with swizzleURLSessionTask: in the same file, which uses SentryNSURLSessionTaskSearch to discover the actual runtime classes. The response capture swizzle skips this step.

4. The existing SentryNetworkTracker already captures almost everything

The existing resume/setState: flow in SentryNetworkTracker.m is rock solid. It already captures URL, method, status code, request/response headers, body sizes — all directly from task properties. The only thing it can't get is the response body bytes (NSData), which is only available in the completion handler.

So the completion handler swizzle is necessary, but it should be minimal: just capture the data and process it right there, rather than building an elaborate bridge back to the setState: path via associated objects.

5. How I got here (prompting approach)

I asked Claude to:

  1. Read swizzleURLSessionDataTasksForResponseCapture and explain it
  2. Give its honest opinion on the approach — it initially said the taskHolder pattern was "clever and correct"
  3. I pushed back on the race condition concern — Claude reconsidered and acknowledged the undocumented timing assumptions
  4. Read all 4 stacked PRs (7582, 7585, 7588, 7590) to trace how the task flows through the stack
  5. Read the full SentryNetworkTracker.m to understand the existing infrastructure
  6. Propose how to merge the new functionality with the existing bulletproof flow

Again: these are Claude-assisted findings. The reasoning is sound to me on a quick read, but please verify independently before making architectural changes based on this.

@43jay
Copy link
Copy Markdown
Collaborator Author

43jay commented Mar 11, 2026

Review notes — treat with care

Disclaimer: I'm on parental leave starting Monday, so I only gave this a quick glance today. Most of the investigation below came from prompting Claude Code — I walked it through the code step by step, asked it to trace the task usage across the PR stack, and challenged its initial assessment when things felt off. The findings are plausible and worth considering, but I haven't verified everything myself. Treat this as "leads worth investigating" rather than definitive conclusions. If needed, I can take another look tomorrow or the day after, but it might be better if @itaybre or @philprime takes this over fully.

TL;DR — suggested restructure

The taskHolder pattern (mutable array to break a chicken-and-egg dependency between the completion handler and the task) feels fishy. The completion handler doesn't actually need the task if you restructure the flow:

  1. Don't use the task as a bridge between request-time and response-time data
  2. Do all replay network detail processing in the completion handler itself — it already has request (captured in swizzle scope), response, and data
  3. Don't piggyback on the setState:/breadcrumb path — the completion handler fires after setState:, so the timing doesn't work anyway

The completion handler swizzle would become a simple, self-contained block with no tricky patterns:

wrapped = ^(NSData *data, NSURLResponse *response, NSError *error) {
    if (!error && data) {
        [networkTracker captureNetworkDetailsForReplayWithRequest:request
                                                        response:response
                                                    responseData:data];
    }
    completionHandler(data, response, error);
};

No taskHolder, no objc_getAssociatedObject lookup in the completion handler, no timing dependencies.

Detailed findings from Claude Code investigation

1. The taskHolder chicken-and-egg pattern

The wrapped completion handler needs a reference to the NSURLSessionDataTask, but the task doesn't exist yet when the handler is constructed. The current solution:

taskHolder = NSMutableArray (empty)
task = SentrySWCallOriginal(request, wrappedHandler)  // wrappedHandler captures taskHolder
[taskHolder addObject:task]
return task

The assumption is: the completion handler will never fire before [taskHolder addObject:task] because the task starts in NSURLSessionTaskStateSuspended and must be resumed first.

Why this is concerning: This relies on an undocumented implementation detail. Apple doesn't guarantee that:

  • A cached response won't trigger the completion handler synchronously during creation
  • An invalid/malformed request won't deliver an error inline before returning
  • An invalidated session won't call back immediately
  • This behavior won't change in a future OS version

If any of these edge cases fire the completion handler during SentrySWCallOriginal, taskHolder.firstObject is nil, and capture silently fails. No crash, just silent data loss — which is worse because you'd never notice.

2. The setState: vs completion handler timing

I asked Claude to trace the execution order. The setState: swizzle fires before the completion handler:

1. Our setState: swizzle fires (task.state is still .running)
2. Original setState: executes (state becomes .completed)
3. Completion handler fires

This means the approach in #7590 (reading SentryReplayNetworkDetails from the task in addBreadcrumbForSessionTask:) would read the associated object before the completion handler has populated the response data. This is a second potential race condition in the stack.

3. Class cluster concern

The swizzle targets [NSURLSession class], but NSURLSession is a class cluster — actual instances are private subclasses (e.g., __NSURLSessionLocal). If those subclasses override dataTaskWithRequest:completionHandler:, the swizzle on the base class won't intercept the calls. Compare with swizzleURLSessionTask: in the same file, which uses SentryNSURLSessionTaskSearch to discover the actual runtime classes. The response capture swizzle skips this step.

4. The existing SentryNetworkTracker already captures almost everything

The existing resume/setState: flow in SentryNetworkTracker.m is rock solid. It already captures URL, method, status code, request/response headers, body sizes — all directly from task properties. The only thing it can't get is the response body bytes (NSData), which is only available in the completion handler.

So the completion handler swizzle is necessary, but it should be minimal: just capture the data and process it right there, rather than building an elaborate bridge back to the setState: path via associated objects.

5. How I got here (prompting approach)

I asked Claude to:

  1. Read swizzleURLSessionDataTasksForResponseCapture and explain it
  2. Give its honest opinion on the approach — it initially said the taskHolder pattern was "clever and correct"
  3. I pushed back on the race condition concern — Claude reconsidered and acknowledged the undocumented timing assumptions
  4. Read all 4 stacked PRs (7582, 7585, 7588, 7590) to trace how the task flows through the stack
  5. Read the full SentryNetworkTracker.m to understand the existing infrastructure
  6. Propose how to merge the new functionality with the existing bulletproof flow

Again: these are Claude-assisted findings. The reasoning is sound to me on a quick read, but please verify independently before making architectural changes based on this.

appreciate the input, will work through it fully. At a glance some is valid and some I already worked through.
edit: worked through it. Responses below

The main issue :

  1. The taskHolder chicken-and-egg pattern

Don't use the task as a bridge between request-time and response-time data
Do all replay network detail processing in the completion handler itself — it already has request (captured in swizzle scope), response, and data

The issue I hit was that NSURLRequest is not enough to differentiate, for example, multiple simultaneous requests with the same parameters - afaict NSURLRequest is basically a URL and an HTTP verb.

The others don't seem relevant or seem inaccurate:

2. The setState: vs completion handler timing

Don't piggyback on the setState:/breadcrumb path — the completion handler fires after setState:, so the timing doesn't work anyway

  1. Our setState: swizzle fires (task.state is still .running)
  2. Original setState: executes (state becomes .completed)
  3. Completion handler fires

This isn't correct based on my local testing. The completionHandler always fired before setState(.completed) runs. This logically makes sense as the app needs to 'handle completion' before the task can be considered 'completed' (edit: Found a counterexample that invalidates this)

Regardless the code is written so that if completionHandler fires before ANY call to setState, then captureResponseDetails call won't find a SentryReplayNetworkDetails and bails

if (!details) {
SENTRY_LOG_DEBUG(@"[NetworkCapture] No SentryReplayNetworkDetails found for %@ - "
@"skipping response capture",
url);
return;
}

3. Class cluster concern

This is our other convo - basically NSURLSession dataTask initializers are NOT currently class clusters (claude misspoke/inaccurate above).

Regardless, the impl might change. The tests added to SentryNSURLSessionTaskSearchTests.swift are meant to uncover this by initializing NSURLSession with different configs to assert that the class returned at run-time has exactly the imp from the base [NSURLSession]

4. The existing SentryNetworkTracker already captures almost everything

This is point 1. The taskHolder chicken-and-egg pattern
Or rather the issue is the same - SentryNetworkTracker (aiui) doesn't have a way to associate a specific NSURLRequest with the completionHandler NSURLResponse

@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 7db5474 to a75e679 Compare March 16, 2026 20:31
@43jay 43jay force-pushed the mobile-935/data-classes branch from a41d68f to 41f8885 Compare March 16, 2026 20:31
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Fabricated request creates inconsistency between swizzled methods
    • Both swizzles now pass task.currentRequest ?: task.originalRequest and the URL-based swizzle no longer fabricates an eager URL-only request.

Create PR

Or push these changes by commenting:

@cursor push 089f8d3da3
Preview (089f8d3da3)
diff --git a/Sources/Sentry/SentrySwizzleWrapperHelper.m b/Sources/Sentry/SentrySwizzleWrapperHelper.m
--- a/Sources/Sentry/SentrySwizzleWrapperHelper.m
+++ b/Sources/Sentry/SentrySwizzleWrapperHelper.m
@@ -129,11 +129,12 @@
             void (^wrappedHandler)(NSData *, NSURLResponse *, NSError *) = nil;
             if (completionHandler) {
                 wrappedHandler = ^(NSData *data, NSURLResponse *response, NSError *error) {
-                    if (!error && data && task) {
+                    NSURLRequest *capturedRequest = task.currentRequest ?: task.originalRequest;
+                    if (!error && data && task && capturedRequest) {
                         [networkTracker captureResponseDetails:data
-                                                     response:response
-                                                      request:request
-                                                         task:task];
+                                                      response:response
+                                                       request:capturedRequest
+                                                          task:task];
                     }
                     completionHandler(data, response, error);
                 };
@@ -158,16 +159,16 @@
         SentrySWArguments(
             NSURL * url, void (^completionHandler)(NSData *, NSURLResponse *, NSError *)),
         SentrySWReplacement({
-            NSURLRequest *request = [NSURLRequest requestWithURL:url];
             __block NSURLSessionDataTask *task = nil;
             void (^wrappedHandler)(NSData *, NSURLResponse *, NSError *) = nil;
             if (completionHandler) {
                 wrappedHandler = ^(NSData *data, NSURLResponse *response, NSError *error) {
-                    if (!error && data && task) {
+                    NSURLRequest *capturedRequest = task.currentRequest ?: task.originalRequest;
+                    if (!error && data && task && capturedRequest) {
                         [networkTracker captureResponseDetails:data
-                                                     response:response
-                                                      request:request
-                                                         task:task];
+                                                      response:response
+                                                       request:capturedRequest
+                                                          task:task];
                     }
                     completionHandler(data, response, error);
                 };

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

@43jay 43jay force-pushed the mobile-935/new-swizzling branch from a75e679 to 75d4331 Compare March 18, 2026 19:25
/**
* Swizzles -[NSURLSession dataTaskWithRequest:completionHandler:] to intercept response data.
*/
+ (void)swizzleDataTaskWithRequestCompletionHandler:(SentryNetworkTracker *)networkTracker
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

h: I would like to see some test verifying the swizzling actually work.
While this looks good, it may break at any point in later versions.

While it is not the same, a strategy similar to SentryNSDataSwizzlingHelperTests.swift could be used to verify the methods are swizzled when executing a datatask

The current tests are verifying the method are changed, but not that they are actually called (what we actually care for)

Once that is added, this would look good to me to merge

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something like the following ? (kind of like an API test / integration test - i.e. use the API and validate that the swizzling callbacks a) occur and ideally b) occur as expected )

test scenario

  1. Initialize a NSUrlSessionDataTask
  2. resume it (or whatever the API is to get it to run)
  3. have it run to completion
  4. verify our completionHandler called, verify the original completion handler called

Couple different versions:
For both newly swizzled initializers:

  1. With networkDetailAllowUrls populated (feature turned on; swizzling active)
  2. With networkDetailAllowUrls populated (feature turned off; swizzling non-existent)

Will do.

if you see this in time => help me by weighing in on whether this sounds like a test that should use an actual server (there is some test server set-up that i haven't needed to use it but will set it up if you say it's the right direction).
Or if the current test harness (à la unit test with mocking) is good enough,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good to me, you can use https://postman-echo.com
If it is flaky we can boot a local server, but I would prefer not to do that if possible

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - PTAL

43jay added 4 commits April 13, 2026 13:44
…onse capture

Add (no-op) callback into SentryNetworkTracker

Remove run-time discovery for swizzle targets; directly swizzle
  [NSURLSession class]
Add unit test to do run-time discovery and report if assumptions invalid
#7584 (comment)
test_dataTaskWithURL_doesNotCallThrough_dataTaskWithRequest
test_dataTaskWithRequest_doesNotCallThrough_dataTaskWithURL
were asserting that one impl does not rely on the other internally.
There's no reason to believe that they do - the test was probably checking
for something that would not happen.
Additionally it was relying on method_setImplementation which could cause
random failures in CI if not cleaned up properly => remove
…wizzling

Verify that the swizzled dataTaskWithRequest:completionHandler:
and dataTaskWithURL:completionHandler: actually fire and populate
network details on breadcrumbs using real HTTP requests to
postman-echo.com.
@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 75d4331 to c24784c Compare April 13, 2026 17:48
@43jay 43jay force-pushed the mobile-935/data-classes branch from 41f8885 to 389f418 Compare April 13, 2026 17:48
@github-actions
Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code can easily blow up and is hard to test. We had severe bugs in the past. Be extra careful when changing these files, and have an extra careful look at these:

  • Sources/Sentry/SentryNetworkTracker.m

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c24784c. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants