-
Notifications
You must be signed in to change notification settings - Fork 211
Skipped Reporting of 302 and Request abort error #4881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
export function cleanupRequests() { | ||
abortController.abort(); | ||
pendingRequests.clear(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this being used anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exported cleanupRequests
function is meant to be called when a component unmounts. It aborts any pending requests and clears the pendingRequests
set to prevent memory leaks or unwanted side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right! Unfortunately I don't see any usages of this function. Makes me wonder whether we really need it, particularly within the scope of this task?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it! I'll go ahead and remove it.
// Reset the flag after navigation is likely complete | ||
setTimeout(() => { | ||
isNavigating = false; | ||
}, 100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the use of a delay here is a reliable way to set the navigation to false. I think it would be better to do this after an abort has been confirmed. You could consider adding an event listener to an controller.signal
instance and do the setting there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right—relying on a fixed delay is not a reliable way to reset the navigation flag. Using an event listener on the AbortController.signal
makes a lot more sense since it ensures the state update happens precisely when the abort is confirmed. I'll update as you suggested.
if ( | ||
isNavigating || | ||
isReloading || | ||
axios.isCancel(error) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's import the isCancel
instead so we can clear the linting error below ie;
import {isCancel} from 'axios'
and this line changes to isCancel(error) ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the suggestion! I'll make sure to update it accordingly.
Hi @akolson , |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes seem to make sense. Thanks @SukhvirKooner. I'll invite @nucleogenesis @AlexVelezLl @ozer550 incase of any further feedback before we proceed with the approval
@SukhvirKooner It looks like the linting check is failing, could you please look into this? Also, @nucleogenesis @AlexVelezLl @ozer550, any additional thoughts on this? |
67a3f38
to
01ee70e
Compare
Hi @akolson, |
const newAbortController = new AbortController(); | ||
abortController.signal = newAbortController.signal; | ||
|
||
// Listen for the abort event to reset the navigation flag | ||
newAbortController.signal.addEventListener('abort', () => { | ||
isNavigating = false; | ||
}); | ||
|
||
// Abort pending requests when navigation begins | ||
abortController.abort(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need a new abort controller here? I'm not super familiar w/ AbortController, but how I read this is that it creates newAbortController
, then sets the abortController.signal
to the default value of a newly created AbortController
instance. Then you put the event listener on that signal using the newAbortController
(which now also sets the listener on the original abortController.signal
unless I'm mistaken) - and then you call the abort()
on the original controller.
So I'm wondering if this was done because you need a fresh AbortSignal
value assigned to the original abortController
value created above for some reason?
If it works it works, but perhaps a comment explaining why we need this temporary abort controller object for it's signal
value alone would be helpful for anybody looking at this in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, The reason for creating a new AbortController
and assigning its signal
to the original one is to ensure that each navigation event gets a fresh AbortSignal. This allows proper cancellation of only the relevant pending requests tied to that specific navigation.
Without a fresh signal, previously aborted requests might interfere with new requests triggered by subsequent navigations. The fresh AbortSignal
ensures each navigation cycle has its own independent abort handling.
I'll add a comment in the code to clarify this for future reference. Thanks again for pointing it out!
@@ -82,6 +129,8 @@ client.interceptors.response.use( | |||
Network: { | |||
lastOffline: lastOffline ? `${Date.now() - lastOffline}ms ago` : 'never', | |||
online: navigator.onLine, | |||
isNavigating, | |||
pendingRequestCount: pendingRequests.size, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there any significance in reporting this to sentry?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reporting isNavigating
and pendingRequestCount
to Sentry could be useful for debugging network-related issues:
isNavigating
: Helps correlate errors with page transitions, potentially revealing issues triggered during navigation.pendingRequestCount
: Shows the number of pending requests when an error occurs, assisting in identifying performance bottlenecks or race conditions.
If there are no related issues currently, we can skip this. However, it might be valuable for future debugging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not entirely sure there is a lot to deduce from these two pieces of information when sent to sentry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a fair point. If these values alone don’t provide enough insight, we could consider pairing them with additional context like error codes to make them more meaningful in Sentry. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think error codes would not make much of a difference. My point is this; we don't need to bloat the sentry reports especially if we are not getting much benefit from the data we are trying to report.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand your point, and I’ll remove this right away to keep the Sentry reports concise and relevant. Let me know if there’s anything else you’d like me to adjust.
Hi @SukhvirKooner! Any progress on this issue? |
Hi @akolson |
Hi @akolson Looking forward to your review and getting this merged! |
Hi, |
Hi @SukhvirKooner! Could you please rebase this with the latest changes in unstable? |
Hi @akolson, I just checked and there haven’t been any updates to the |
Hi @SukhvirKooner ! The goal of the rebase is to keep your branch up to date. Because it's stayed out of Also, could you please outline clear steps on how to manually test your PR--unless I missed them, It didn't get the sense that they were included. Could you please be more explicit by adding a "review guidance" section? |
8a5e9e0
to
40ec9a7
Compare
Hi @akolson |
Hi @akolson , |
@coderabbitai full review |
const newAbortController = new AbortController(); | ||
abortController.signal = newAbortController.signal; | ||
|
||
// Abort pending requests when navigation begins |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets remove this comment. The code is self explanatory
abortController.abort(); | ||
}); | ||
|
||
// Add request interceptor to track pending requests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
// Add request interceptor to track pending requests | ||
client.interceptors.request.use(config => { | ||
// Add signal to the request config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -38,24 +38,59 @@ window.addEventListener('offline', () => { | |||
lastOffline = Date.now(); | |||
}); | |||
|
|||
const pendingRequests = new Set(); | |||
|
|||
// Create an AbortController for managing pending requests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pendingRequests.delete(error.config); | ||
} | ||
|
||
// Ignore specific types of errors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Ignore specific types of errors | ||
if ( | ||
isCancel(error) || | ||
(error.response && [302, 403, 404, 405, 412].includes(error.response.status)) // added 302 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed all the mentioned comments. Please let me know if any others still need to be removed. |
client.interceptors.response.use( | ||
response => response, | ||
response => { | ||
// Remove from pending requests on success |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets remove this too!
const status = error.response?.status || 0; | ||
|
||
// Suppress contentnode query errors | ||
if (url.includes('contentnode')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know status error code the affected url returns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aborted requests never actually hit the server, so there is no HTTP status code returned. In the Network tab you’ll just see (canceled), and in our interceptor error.response will be undefined. Axios then falls back to status = 0 and throws a CanceledError with error.code === 'ERR_CANCELED'.
That’s exactly why our suppression logic uses:
if (isCancel(error)) {
return Promise.reject(error);
}
rather than checking for a particular HTTP response code. Any request you manually abort (or that gets aborted by navigation) will show up as status 0 or ERR_CANCELED, so it’s correctly caught by isCancel(error) and never forwarded to Sentry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed 💯.
So do we still need to specifically do if (url.includes('contentnode')) {
when if (isCancel(error)) {
is doing this for us?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes – we still need both guards, because they cover different noise:
-
isCancel(error) catches aborted requests (status 0, ERR_CANCELED)
-
url.includes('contentnode') silences real HTTP errors from our content‑node API that are "safe to ignore"
Removing the contentnode check may flood Sentry with expected CMS glitches, removing isCancel would report every navigation‑cancelled request. We need them both.
But if u think that's still not needed , I'll be happy to remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually think it is the same thing based on your explanation 🙂. I think we should remove this check. I also think it is a rigid check -- it would fail for other APIs that don't contain the contentnode
path with the same failure scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can always add this back if sentry says otherwise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally fair, makes sense to remove it for now. we can always revisit.
Hi @SukhvirKooner! |
Thanks! This was the approach I came up with to test that the request abort suppression is working as expected. I’ll also look into whether there’s a way to test this without making any changes in the PR code itself. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Thanks and Great work @SukhvirKooner. Sukhvir added some reviewer guidance though I think it it more developer focused. The most effective way for QA to test this is to check the sentry reports (after going through several workflows) to see if any of the suppressed errors show up there again. If they don't we can assume the issue has been resolved. cc @radinamatic @pcenov
Fixes: #4873
Summary
Redirect requests (301/302)
Before


After
I have successfully resolved the 302 redirect request issue by updating the Axios error handling logic. Specifically, I added 302 to the list of status codes that should bypass error logging:
(error.response && [302, 403, 404, 405, 412].includes(error.response.status))
This ensures that when a 302 status is returned, Axios will handle it gracefully without triggering unnecessary error logs or forwarding it to Sentry.
Request aborted Error
Error ScreenShort

I have made the key changes to the original code to handle the Error particular during navigation:
const abortController = new AbortController();
Despite these suppression mechanisms, legitimate errors unrelated to Request aborted or Redirect requests (301/302) will still be logged and captured in Sentry for further monitoring and troubleshooting.
Review guidance
1. Rebuild with PR changes
2. Add debug logs
Test request abort suppression
[DEBUG] request canceled or ignored: canceled
No
[SENTRY] WOULD REPORT:
line should appear.This confirms that manually aborted requests are successfully caught and suppressed before they can be reported to Sentry. By logging only
[DEBUG] request canceled or ignored
and not triggering the[SENTRY] WOULD REPORT: log