You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[MAUI] Local scope tags leak into subsequent HttpClient auto captured events #4610
Reported via Zendesk ticket: Tags set inside the local scope callback of SentrySdk.CaptureException(error, scope => { ... }) are appearing on automatically captured HttpClient events. The tag (lats.EventName) is only set within the local callback and not configured globally, and it bleeds into later auto captured events.
Make a failing HTTP request (404) inside a try/catch. In catch, call: SentrySdk.CaptureException(ex, scope => { scope.SetTags(SetExtra(apiMethod, "http.error")); });
This correctly sends an event with tag lats.EventName=testtag.
Make another failing HTTP request (500). The HttpClient integration automatically captures an event.
That event still includes the tag lats.EventName=testtag even though it wasn’t set globally.
Expected Result
Tags set in a local scope callback should not bleed to other automatically captured events.
Actual Result
The automatically captured HttpClient event inherits tags from the local scope, even though that scope should have been isolated.
Hi @jamescrosswell. I'm the one who reported it. I'll just copy and paste my email with all the details I sent earleir to @kerenkhatiwada:
===========
Here is exact code how all http related error events are being communicated from my app to Sentry.
public override void LogApiError(Exception error, string apiMethod, string apiFullUrl,
[Optional] string? payload,
[CallerMemberName] string? callerFunction = null,
[CallerFilePath] string? callerFile = null)
{
base.LogApiError(error, apiMethod, apiFullUrl, payload, callerFunction, callerFile);
if (settingsService.HandledErrorsTelemetry)
{
SentrySdk.CaptureException(error, scope =>
{
scope.Contexts.Add("Error Payload", BuildContext(null, apiFullUrl, callerFunction, callerFile, Sanitize(payload!, apiMethod), null));
// Here I set tags, one of them is lats.EventName that sparked this help request
scope.SetTags(SetExtra(apiMethod, "http.error"));
});
// disregard this block - it's my attempt to mitigate the situation
//SentrySdk.ConfigureScope(scope =>
//{
// scope.SetTag("lats.EventName", "PreviousNameIsReset");
//});
}
}
The above function is called from the try/catch block when some exception arises, like this:
// function
Try
{
execute httpClient post or get something that will fail on the server
}
catch (HttpRequestException ex)
{
diagnostics.LogApiError(ex, request.MethodName, targetUrl, $"\nREQUEST {jsonRequest}\nRESPONSE {jsonResponse}", caller);
}
So, the above setup is pretty standard and boring. Now, to replicate, we need to execute two sequential calls that will all fail on the server:
So, to reiterate, my question is about step #2 - why does the Sentry report retains the tag that was set on the previous call presumably on a local to the call scope?
===========
Something like that. I hope I am not misreading the documentation about hub and scope. The way I understand it, the line
SentrySdk.CaptureException(error, scope => ...
makes whatever tags are set to be local to this particular call.
@Flash0ver I think you'll have to look into this. I don't have access to any of the events @MichaelShapiro is referencing.
As I say, I can't see logically how the result of the scope delegate could end up being applied to a different event (our code creates a clone of the underlying scope before invoking the delegate).
@jamescrosswell You are right - I should've be prepared with a repo, my bad. Sorry for that. So, as I was concocting small repro last night I stumbled on an important detail that I missed before - I think it's important to surface it here. Console program won't be able to help here because ... this situation occurs ONLY when executing http request on MAUI/iOS.
So, same code base, same Sentry settings etc. Calling two sequential https request. both should fail.
On Android each failure is "catch"ed predictably by my code and Sentry event sent the way I intended with tags I supplied.
On iOS, in addition to predictably "catch"ed exception and correctly sent to Sentry, there are two additional events sent to Sentry. These are the events in question and the reason for this issue.
Additionally, if I explicitly turn off this option sentryOptions.CaptureFailedRequests = false then iOS behaves identical to Android - no extra and uncontrolled events are sent to Sentry. I didn't realize that the above property was true by default.
So, if still needed, I'd have to create small repro but it has to be a full MAUI mobile app program. But I still hope that the additional details above might help you to isolate the issue as I am not sure how quickly I can do this small repro this week.
@jamescrosswell I have a repo for you. It requires a security token to run against my server here. I couldn't make it replicatable without the actual connection:( I'll provide both to you - repository and the temp token - whenever you have a chance to take a look at it. Thank you so much.
Thanks @MichaelShapiro, that would be fantastic. I can take a look this week some time. You could DM me the connection details via Discord if you like. My handle is @wingfoiladdict.
Would it be passible to send you email instead? I'm not on discord and I tried to send you friend request. That place seems very confusing (or maybe I'm just old fashioned:)
@MichaelShapiro thanks for providing the repro. I couldn't get it working with the token that you provided (everything just timed out after 60 seconds when I used that) but I got the general gist of what you were trying to do and managed to reproduce using a fake message handler instead of your real world service + token.
usingSystem.Net;usingSystem.Net.Http.Json;namespaceSentryMAUI4610;publicpartialclassMainPage{privatereadonlyHttpClient_httpClient;publicMainPage(){InitializeComponent();varfakeHandler=newFakeHttpMessageHandler(request =>{varresponseCode=request.RequestUri.AbsolutePath.Contains("NotPresent")?404:500;returnnewHttpResponseMessage((HttpStatusCode)responseCode);});varsentryHandler=newSentryHttpMessageHandler(fakeHandler);_httpClient=newHttpClient(sentryHandler);}privatevoidApiRequest01(object?sender,EventArgse){// this call simulates a 404 response and reports such to SentryCallApi("https://localhost/NotPresent","NotPresent");}privatevoidApiRequest02(object?sender,EventArgse){// this call simulates a 500 response and reports such to SentryCallApi("https://localhost/Catastrophic","Catastrophic");}privateasyncvoidCallApi(stringurl,stringrequestName){try{usingvarhttpResponse=await_httpClient.PostAsJsonAsync(url,"foo");httpResponse?.EnsureSuccessStatusCode();Console.WriteLine($"CallAPI - success");}catch(Exceptionex){Console.WriteLine($"CallAPI - error: {ex.Message}");SentrySdk.CaptureException(ex, scope =>{scope.SetTag("MyTag",requestName);scope.SetTag("MyUrl",url);});}}}publicclassFakeHttpMessageHandler(Func<HttpRequestMessage,HttpResponseMessage>getResponse):DelegatingHandler{protectedoverrideTask<HttpResponseMessage>SendAsync(HttpRequestMessagerequest,CancellationTokencancellationToken)=>Task.FromResult(getResponse?.Invoke(request)??newHttpResponseMessage(HttpStatusCode.OK));protectedoverrideHttpResponseMessageSend(HttpRequestMessagerequest,CancellationTokencancellationToken)=>getResponse?.Invoke(request)??newHttpResponseMessage(HttpStatusCode.OK);}
From what I can tell, everything is working as it should in the SDK and Tags are not bleeding over from one event to another.
However the UI in Sentry is confusing.
Firstly, it groups all of the events together... not in and of itself a problem:
When you click on an event however, you can click on the next/previous buttons to view subsequent/previous versions of that event. When doing so, the title itself doesn't update (it shows the description for whatever the first event was). So you can end up with a discrepancy between the event you think you're looking at and the one you're actually looking at.
Below, for example, is what I see when having clicked on the Latest event from the dashboard (so that was the first event I looked at - that was a 500 Internal Server Error) and subsequently having navigated to view the First event in that series/group (which was a 404 Not Found):
At that point, if you navigate to the Tags and look at them, what you see in the tags will no longer match the title that is shown in the UI - which makes you think the tags are bleeding over from one event to the next.
Short term workaround
Ignore the title - this can't be trusted... only look at the Stack Trace (this is always accurate).
Long term workaround
I'll raise an issue with the team that maintains the Sentry portal itself.
Activity
linear commentedon Oct 8, 2025
NET-487
jamescrosswell commentedon Oct 8, 2025
Looking at the code, I can't see how this would be possible:
sentry-dotnet/src/Sentry/Internal/Hub.cs
Lines 515 to 533 in 9e2f5f2
Can we get a bit of sample code that reproduces the problem to investigate further?
MichaelShapiro commentedon Oct 8, 2025
Hi @jamescrosswell. I'm the one who reported it. I'll just copy and paste my email with all the details I sent earleir to @kerenkhatiwada:
===========
Here is exact code how all http related error events are being communicated from my app to Sentry.
The above function is called from the try/catch block when some exception arises, like this:
// function
Try
{
execute httpClient post or get something that will fail on the server
}
catch (HttpRequestException ex)
{
diagnostics.LogApiError(ex, request.MethodName, targetUrl, $"\nREQUEST {jsonRequest}\nRESPONSE {jsonResponse}", caller);
}
So, the above setup is pretty standard and boring. Now, to replicate, we need to execute two sequential calls that will all fail on the server:
So, to reiterate, my question is about step #2 - why does the Sentry report retains the tag that was set on the previous call presumably on a local to the call scope?
===========
Something like that. I hope I am not misreading the documentation about hub and scope. The way I understand it, the line
SentrySdk.CaptureException(error, scope => ...
makes whatever tags are set to be local to this particular call.
Let me know if I can answer any more questions.
jamescrosswell commentedon Oct 9, 2025
@Flash0ver I think you'll have to look into this. I don't have access to any of the events @MichaelShapiro is referencing.
As I say, I can't see logically how the result of the scope delegate could end up being applied to a different event (our code creates a clone of the underlying scope before invoking the delegate).
6 remaining items
MichaelShapiro commentedon Oct 9, 2025
@jamescrosswell You are right - I should've be prepared with a repo, my bad. Sorry for that. So, as I was concocting small repro last night I stumbled on an important detail that I missed before - I think it's important to surface it here. Console program won't be able to help here because ... this situation occurs ONLY when executing http request on MAUI/iOS.
So, same code base, same Sentry settings etc. Calling two sequential https request. both should fail.
On Android each failure is "catch"ed predictably by my code and Sentry event sent the way I intended with tags I supplied.
On iOS, in addition to predictably "catch"ed exception and correctly sent to Sentry, there are two additional events sent to Sentry. These are the events in question and the reason for this issue.
Additionally, if I explicitly turn off this option
sentryOptions.CaptureFailedRequests = falsethen iOS behaves identical to Android - no extra and uncontrolled events are sent to Sentry. I didn't realize that the above property was true by default.So, if still needed, I'd have to create small repro but it has to be a full MAUI mobile app program. But I still hope that the additional details above might help you to isolate the issue as I am not sure how quickly I can do this small repro this week.
Thank you.
MichaelShapiro commentedon Oct 9, 2025
@jamescrosswell I have a repo for you. It requires a security token to run against my server here. I couldn't make it replicatable without the actual connection:( I'll provide both to you - repository and the temp token - whenever you have a chance to take a look at it. Thank you so much.
jamescrosswell commentedon Oct 12, 2025
Thanks @MichaelShapiro, that would be fantastic. I can take a look this week some time. You could DM me the connection details via Discord if you like. My handle is
@wingfoiladdict.MichaelShapiro commentedon Oct 13, 2025
Would it be passible to send you email instead? I'm not on discord and I tried to send you friend request. That place seems very confusing (or maybe I'm just old fashioned:)
jamescrosswell commentedon Oct 13, 2025
@MichaelShapiro thanks for providing the repro. I couldn't get it working with the token that you provided (everything just timed out after 60 seconds when I used that) but I got the general gist of what you were trying to do and managed to reproduce using a fake message handler instead of your real world service + token.
From what I can tell, everything is working as it should in the SDK and Tags are not bleeding over from one event to another.
However the UI in Sentry is confusing.
Firstly, it groups all of the events together... not in and of itself a problem:
When you click on an event however, you can click on the next/previous buttons to view subsequent/previous versions of that event. When doing so, the title itself doesn't update (it shows the description for whatever the first event was). So you can end up with a discrepancy between the event you think you're looking at and the one you're actually looking at.
Below, for example, is what I see when having clicked on the Latest event from the dashboard (so that was the first event I looked at - that was a 500 Internal Server Error) and subsequently having navigated to view the First event in that series/group (which was a 404 Not Found):
At that point, if you navigate to the Tags and look at them, what you see in the tags will no longer match the title that is shown in the UI - which makes you think the tags are bleeding over from one event to the next.
Short term workaround
Ignore the title - this can't be trusted... only look at the Stack Trace (this is always accurate).
Long term workaround
I'll raise an issue with the team that maintains the Sentry portal itself.