Open Bug 1280189 Opened 8 years ago Updated 9 months ago

[Fetch] "NetworkError when attempting to fetch resource" exception when redirecting


(Core :: DOM: Networking, defect, P3)

47 Branch




(Reporter: christian.hersevoort, Unassigned)


(Blocks 1 open bug)


(Whiteboard: [necko-triaged][necko-next])


(1 file)

User Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36

Steps to reproduce:

I created a simple script to reproduce this issue:

What it does is:
1. Start a Fetch-request 
2. Open a link or redirect to another page before fetch finishes

Actual results:

Get exception "NetworkError when attempting to fetch resource" on the fetch.catch() handler

Expected results:

The canceled fetch-request should not throw an exception
We purposely abort network when the page is navigated.

Are you saying the network should continue or we should just not reject the promise?  Do you see different behavior with XHR, for example?
Flags: needinfo?(christian.hersevoort)
is the sw the right component for fetch issues?
Component: Networking: HTTP → DOM: Service Workers
Close.  Just DOM unless the site is actually using service workers.  I don't think it is in this case.
Component: DOM: Service Workers → DOM
My initial assumption was a wrong. This issue is about the timing of the exception and not specifically about fetch. 

Let me reiterate:

What it does is:
1. Start async request (fetch or XHR)
2. Open a link / Redirect to another page
3. Fetch or XHR gets rejected
3b: Page shows error to the user (because a promise was rejected)
4. New page is opened

Expected results:
1. Start async request (fetch or XHR)
2. Open a link / Redirect to another page
3. New page is opened
4. Fetch or XHR gets rejected

Note: The XHR should be rejected AFTER the new 'old' page is closed, therefore it won't show the user an error message. From a developer point of view it's not possible to distinguish between an actual error or and expected redirect.

I've updated the example ( For clarity I've added an jQuery ajax (XHR) example as well. The jQuery example has the same bug.
Flags: needinfo?(christian.hersevoort)
Olli, what do you think?  Are we aborting our nsILoadGroup too early?  Should we be waiting for the new document to become active?
Flags: needinfo?(bugs)
Per spec, the old document's network stuff gets stopped before the fetch of the new document _starts_.  See step 11 which calls which in step 2 does:

  Cancel any instances of the fetch algorithm in the context of this Document, discarding any tasks queued
  for them, and discarding any further data received from the network for them.

So if there is a rejection that's going to happen here, it would happen before the fetch of the new document starts.  So the "expected results" from comment 4 are definitely wrong.  The only possibly spec-compliant things are the "what it does" list or the same thing without step 3/3b if the fetch being canceled is not supposed to reject the promise.
Oh, and at least at one point Chrome did _not_ implement the spec correctly in terms of aborting the document, as I understand.  I don't know whether they do now.

Last I checked, Safari did implement the spec correctly, but neither Safari nor WebKit nightly implements fetch, so it's hard to test this there.
I suspect this issue is causing my progressive web app to no longer work offline.

It used to in nightly on android and linux, now both don't.

I am still investigating and would appreciate any guidance in working around this.

I am basically using a pattern like

But now I get the error described here instead of a fallback to the cached file when network is down.
Can you provide a link to your site or a demo?  Does this reproduce in developer edition or beta?
Flags: needinfo?(adrian.aichner)
(In reply to Ben Kelly [:bkelly] from comment #9)
> Can you provide a link to your site or a demo?  Does this reproduce in
> developer edition or beta?

My app is fairly involved and not public.

I saw this breakage in firefox for android 48.0b10 as well.

One other thing I noticed meanwhile is that offline access does not seem to work while devtools are open in that tab. I toggle devtools off with Ctrl+Shift+I and I can you the cached app offline.

I went from the "fastest" strategy I had used before to the approach used by
with caching added in the then clause:

this.addEventListener('fetch', function(event) {
  var request = event.request;
  var url = request.url;
    fetch(event.request).then(function(response) {
      if (request.method == 'GET' && response && successResponses.test(response.status) &&
          request.url.match(this.registration.scope) &&
          (response.type == 'basic' || /\.(js|png|ttf|woff|woff2)/i.test(request.url) ||
           /fonts\.googleapis\.com/i.test(request.url))){ {
          console.log(`put ${event.request.url} in ${version}`);
          cache.put(event.request, response.clone());
      return response;
    }).catch(err => {
      console.log(JSON.stringify(err, Object.getOwnPropertyNames(Error.prototype), 2));
        console.log(`return cache.match(${url}) since fetch fails`);
        return cache.match(url);
      }).catch(err => {
        console.log(JSON.stringify(err, Object.getOwnPropertyNames(Error.prototype), 2));
Flags: needinfo?(adrian.aichner)
Can you try to make a minimal test case?  Its really hard to investigate without being able to reproduce the error.  The linked SW demo works fine for me.

Also, are you creating iframes or anything?  This bug is about windows that are being closed.  Do you have such windows that are being closed?
Flags: needinfo?(adrian.aichner)
(In reply to Ben Kelly [:bkelly] from comment #11)
> Can you try to make a minimal test case?  Its really hard to investigate

I'll see whether I can file new coherent bugs, be it devtools or fetch implementation or whatever I may find.

Perhaps I find a public testcase which exposes the problem I was seeing.

> without being able to reproduce the error.  The linked SW demo works fine
> for me.

Yes, that works for me too and is what I based my reworked code on.

> Also, are you creating iframes or anything?  This bug is about windows that
> are being closed.  Do you have such windows that are being closed?

No iframes, no closing windows.

I only found this bug based on the matching error type and message.
Flags: needinfo?(adrian.aichner)
I am also seeing this, and it is quite irritating. Fetch requests error out with "TypeError: NetworkError when attempting to fetch resource" whenever the user navigates away while there is an ongoing async fetch request. 

Since I am showing a an error message on NetworkError to users this means the user gets flashed with an error message every time they navigate if there is an ongoing fetch request in the background. Beyond flashing an incorrect error message to the user my logs fill up with false NetworkError reports. 

Neither Chrome nor Safari does this. 

I am not sure what the ideal solution would be, but throwing an NetworkError when the user cancels the request is just wrong. At the very least it should do something that lets me distinguish an actual error from an canceled network request.
Johan, can you work around the issue by having a small delay between fetch() rejection and showing the error?  Maybe you could suppress the visual error if you get pagehide event?  Not sure on the timing you are seeing.

Anne, is there anything in the spec AFAIK that would require the browser not to reject fetch() promises when the window navigates?
Flags: needinfo?(annevk)
AFAYK I guess?

We added a keepalive member that you can set to true. I suspect the problem here is comment 7. That the timing when requests are aborted is off between Firefox and other browsers.
Flags: needinfo?(annevk)
Problem with pagehide is that it fires after the promise has been rejected and the error show. The promise is also rejected with NetworkError if the user simply hits stop to stop loading the page, in which case pagehide is never fired.
Now that we have abortable fetch we could possibly reject these fetch() calls with AbortError instead of NetworkError.  (This might already happen in FF 57+.) This would let you ignore the AbortError specifically, but report network problems.
I tested and we do fire AbortError when a fetch() is aborted due to navigation.  I did:

1. open this site in FF57:
2. start fetching
3. open web console and run: window.location = ''
4. observe that the AbortError rejection is displayed briefly before the new page is shown

Johan, does this help with your issue?
Flags: needinfo?(johan.sigfrids)
Yes, throwing a distinguishable AbortError on navigation does solve the problem for me.
Flags: needinfo?(johan.sigfrids)
Thanks!  I'm going to close this for now then since the AbortError logic is landed and will be shipping in FF57.
Closed: 7 years ago
Flags: needinfo?(bugs)
Resolution: --- → WORKSFORME
This bug doesn't seem to be fixed.

I combined your example with mine and it's still broken.

I made 3 cases:
1) Slow fetch + redirect to => Not working: Error flash + NetworkError
2) Slow fetch with try-catch + redirect => No error flash, but I still get a NetworkError in the console
3) Slow fetch with try-catch using async await => Error flash + NetworkError

Am I doing something wrong? I've tested it on FF57 and FF58.

The jQuery example also doesn't work in Firefox. (it works fine in Chrome)
Resolution: WORKSFORME → ---
Flags: needinfo?(bkelly)
Priority: -- → P2
Andrea, do you have any thoughts on comment 21?  I'm not going to have time to look at this.
Flags: needinfo?(bkelly) → needinfo?(amarchesini)
Component: DOM → DOM: Core & HTML

I believe I am still seeing this issue as well on Firefox 68. Here's my small repro:

When I watch the debugger when executing this fiddle, I get:

navigating away
caught TypeError: "NetworkError when attempting to fetch resource." TypeError

I see a TypeError instead of an AbortError

So is the issue in comment 23 just that the rejection is with a TypeError, not an AbortError?

Flags: needinfo?(Stephen)

(In reply to Boris Zbarsky [:bzbarsky, bz on IRC] from comment #24)

So is the issue in comment 23 just that the rejection is with a TypeError, not an AbortError?

Yes. comment 18 sounds like there was a change in FF57 that would cause an AbortError. Today in FF68, running the repro from comment 18 and my repro in comment 23 result in a TypeError, not AbortError.

Flags: needinfo?(Stephen)

OK. Andrew, do we want to just mutate this to do the "fire AbortError" thing, or should that be a separate bug (and mark this one invalid, since we do in fact want to terminate fetches on navigation)?

I should note that calling window.stop() while fetching on throws a TypeError in Chrome and Safari, so we may need to file bugs on them too... It does look to me like the Fetch spec says to reject with an AbortError DOMException in that case, right?

Component: DOM: Core & HTML → DOM: Networking
Flags: needinfo?(bugmail)
Flags: needinfo?(annevk)
Ever confirmed: true

I think so, yes. Jake designed this and I thought he also added tests for this scenario, but maybe not.

Flags: needinfo?(annevk) → needinfo?(jaffathecake)
Priority: P2 → P3
Whiteboard: [necko-triaged]
Severity: normal → S4

In Firefox 94.0.2, reloading or clicking a link while a fetch request is being processed still throws a NetworkError. To reproduce, carry out any slow fetch and reload before it is complete.

Any progress with this here? I am getting this error a lot now (FF 100.01... )

We have trouble with this too. At least this request could be marked as 'aborted' not as an 'error' to handle ist correctly.

Blocks: fetch

Hi, Is this still being worked on or is there a work around to handles NetworkError for this case only? Our monitoring system is logging a lot of NetworkError errors because of this and we don't have a clear way of handling them without missing on the actual NetworkErrors.

Redirect a needinfo that is pending on an inactive user to the triage owner.
:jesup, since the bug has recent activity, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(jaffathecake) → needinfo?(rjesup)

This still seems like it's something that we're following the spec on, and chrome & safari aren't, correct Olli?

Is there work to do here that would help with regards to AbortError? (see comment 25)

Flags: needinfo?(smaug)
Flags: needinfo?(rjesup)
Flags: needinfo?(krosylight)
Flags: needinfo?(amarchesini)
Attached file 1280189.html

Attaching the repro in comment #23 as a static file.

The error is from mPromise->MaybeRejectWithTypeError<MSG_FETCH_FAILED>(); where the stack is:

xul.dll!mozilla::dom::MainThreadFetchResolver::OnResponseAvailableInternal(mozilla::SafeRefPtr<mozilla::dom::InternalResponse> aResponse) Line 761 (c:\Users\sasch\Documents\GitHub\gecko-dev\dom\fetch\Fetch.cpp:761)
xul.dll!mozilla::dom::FetchDriverObserver::OnResponseAvailable(mozilla::SafeRefPtr<mozilla::dom::InternalResponse> aResponse) Line 346 (c:\Users\sasch\Documents\GitHub\gecko-dev\dom\fetch\Fetch.cpp:346)
xul.dll!mozilla::dom::FetchDriver::FailWithNetworkError(nsresult rv) Line 943 (c:\Users\sasch\Documents\GitHub\gecko-dev\dom\fetch\FetchDriver.cpp:943)
xul.dll!mozilla::dom::FetchDriver::OnStartRequest(nsIRequest * aRequest) Line 979 (c:\Users\sasch\Documents\GitHub\gecko-dev\dom\fetch\FetchDriver.cpp:979)
xul.dll!nsCORSListenerProxy::OnStartRequest(nsIRequest * aRequest) Line 512 (c:\Users\sasch\Documents\GitHub\gecko-dev\netwerk\protocol\http\nsCORSListenerProxy.cpp:512)
xul.dll!mozilla::net::HttpChannelChild::DoNotifyListener() Line 1252 (c:\Users\sasch\Documents\GitHub\gecko-dev\netwerk\protocol\http\HttpChannelChild.cpp:1252)
xul.dll!mozilla::net::HttpAsyncAborter<mozilla::net::HttpChannelChild>::HandleAsyncAbort() Line 1119 (c:\Users\sasch\Documents\GitHub\gecko-dev\obj-x86_64-pc-windows-msvc\dist\include\mozilla\net\HttpBaseChannel.h:1119)
xul.dll!mozilla::net::HttpChannelChild::HandleAsyncAbort() Line 1135 (c:\Users\sasch\Documents\GitHub\gecko-dev\netwerk\protocol\http\HttpChannelChild.cpp:1135)
xul.dll!mozilla::net::HttpChannelChild::FailedAsyncOpen(const nsresult & status) Line 1158 (c:\Users\sasch\Documents\GitHub\gecko-dev\netwerk\protocol\http\HttpChannelChild.cpp:1158)
xul.dll!mozilla::net::HttpChannelChild::RecvFailedAsyncOpen::<lambda_24>::operator()() Line 1127 (c:\Users\sasch\Documents\GitHub\gecko-dev\netwerk\protocol\http\HttpChannelChild.cpp:1127)
xul.dll!std::invoke<`lambda at C:/Users/sasch/Documents/GitHub/gecko-dev/netwerk/protocol/http/HttpChannelChild.cpp:1125:13' &>(mozilla::net::HttpChannelChild::RecvFailedAsyncOpen::<lambda_24> & _Obj) Line 1524 (c:\Users\sasch\.mozbuild\vs\VC\Tools\MSVC\14.29.30133\include\type_traits:1524)
xul.dll!std::_Invoker_ret<void,1>::_Call<`lambda at C:/Users/sasch/Documents/GitHub/gecko-dev/netwerk/protocol/http/HttpChannelChild.cpp:1125:13' &>(mozilla::net::HttpChannelChild::RecvFailedAsyncOpen::<lambda_24> & _Func) Line 652 (c:\Users\sasch\.mozbuild\vs\VC\Tools\MSVC\14.29.30133\include\functional:652)
xul.dll!std::_Func_impl_no_alloc<`lambda at C:/Users/sasch/Documents/GitHub/gecko-dev/netwerk/protocol/http/HttpChannelChild.cpp:1125:13',void>::_Do_call() Line 822 (c:\Users\sasch\.mozbuild\vs\VC\Tools\MSVC\14.29.30133\include\functional:822)
xul.dll!std::_Func_class<void>::operator()() Line 869 (c:\Users\sasch\.mozbuild\vs\VC\Tools\MSVC\14.29.30133\include\functional:869)
xul.dll!mozilla::net::ChannelFunctionEvent::Run() Line 55 (c:\Users\sasch\Documents\GitHub\gecko-dev\obj-x86_64-pc-windows-msvc\dist\include\mozilla\net\ChannelEventQueue.h:55)
xul.dll!mozilla::net::ChannelEventQueue::RunOrEnqueue(mozilla::net::ChannelEvent * aCallback, bool aAssertionWhenNotQueued) Line 248 (c:\Users\sasch\Documents\GitHub\gecko-dev\obj-x86_64-pc-windows-msvc\dist\include\mozilla\net\ChannelEventQueue.h:248)
xul.dll!mozilla::net::HttpChannelChild::RecvFailedAsyncOpen(const nsresult & aStatus) Line 1124 (c:\Users\sasch\Documents\GitHub\gecko-dev\netwerk\protocol\http\HttpChannelChild.cpp:1124)
xul.dll!mozilla::net::PHttpChannelChild::OnMessageReceived(const IPC::Message & msg__) Line 532 (c:\Users\sasch\Documents\GitHub\gecko-dev\obj-x86_64-pc-windows-msvc\ipc\ipdl\PHttpChannelChild.cpp:532)
xul.dll!mozilla::dom::PContentChild::OnMessageReceived(const IPC::Message & msg__) Line 8818 (c:\Users\sasch\Documents\GitHub\gecko-dev\obj-x86_64-pc-windows-msvc\ipc\ipdl\PContentChild.cpp:8818)
xul.dll!mozilla::dom::ContentChild::OnMessageReceived(const IPC::Message & aMsg) Line 3765 (c:\Users\sasch\Documents\GitHub\gecko-dev\dom\ipc\ContentChild.cpp:3765)
xul.dll!mozilla::ipc::MessageChannel::DispatchAsyncMessage(mozilla::ipc::ActorLifecycleProxy * aProxy, const IPC::Message & aMsg) Line 1811 (c:\Users\sasch\Documents\GitHub\gecko-dev\ipc\glue\MessageChannel.cpp:1811)

And the spec says in step 12.3:

If response is a network error, then reject p with a TypeError and abort these steps.

So the error being TypeError is probably fine. But I think the core issue is that we get an error when Blink does not, rather than the type of the error?

Flags: needinfo?(krosylight)

Also the spec:

The user agent may terminate an ongoing fetch if that termination is not observable through script.

(Example) The user agent cannot terminate the fetch because the termination can be observed through the promise.

So we incorrectly expose the termination as a form of error.

(In reply to Kagami [:saschanaz] from comment #36)

So we incorrectly expose the termination as a form of error.

I guess that suggests that FetchDriver should specially handle NS_BINDING_ABORTED to eat the error and potentially neuter the promise if we think this is from coming from some variation of the load group canceling everything (also happens in the LoadGroup destructor, or maybe there are other ways for it to happen too?).

Flags: needinfo?(bugmail)
Flags: needinfo?(smaug)
Whiteboard: [necko-triaged] → [necko-triaged][necko-priority-review]
Whiteboard: [necko-triaged][necko-priority-review] → [necko-triaged][necko-next]
You need to log in before you can comment on or make changes to this bug.