puppeteer: `Navigation Timeout Exceeded` when using `networkidle0` and no insight into what timed out

Steps to reproduce

Tell us about your environment:

What steps will reproduce the problem?

'use strict'
const puppeteer = require('puppeteer')
;(async () => {
  const browser = await puppeteer.launch({})
  const page = await browser.newPage()
  await page.setRequestInterception(true)
  page.on('request', request => request.continue())

  try {
    await page.goto('https://songsear.ch/', {
      waitUntil: 'networkidle0',    // fails
      // waitUntil: 'networkidle2',    // works
      timeout: 2000
    })
  } catch (ex) {
    await browser.close()
    console.warn('IT FAILED')
    console.error(ex.toString())
    throw ex
  }
  await browser.close()
})()

RUnning this:

▶ node --trace-warnings hack.js
IT FAILED
Error: Navigation Timeout Exceeded: 2000ms exceeded
(node:58887) Error: Navigation Timeout Exceeded: 2000ms exceeded
    at Promise.then (/Users/peterbe/dev/JAVASCRIPT/minimalcss/node_modules/puppeteer/lib/NavigatorWatcher.js:71:21)
    at <anonymous>
(node:58887) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    at emitWarning (internal/process/promises.js:69:15)
    at emitPendingUnhandledRejections (internal/process/promises.js:86:11)
    at runMicrotasksCallback (internal/process/next_tick.js:124:9)
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickCallback (internal/process/next_tick.js:180:9)

This fails every time. It doesn’t matter if I change 2000 to 20000 or 30000.

If you change from networkidle0 to networkidle2 it works every time. But that’s not a “solution” because I like networkidle0 since I want to wait for all its resources to be downloaded so they can be analyzed and stuff. That “requirement” is not included in the script above.

The origin of this problem is here: https://github.com/peterbe/minimalcss/issues/112

Running that failing script with full debugging turns up this: https://gist.githubusercontent.com/peterbe/c7c21131fbe23031034fea114dfd6b97/raw/1f0a8329bb74127f9cb286f727f4b3246a43b70e/default.txt

What is the expected result? Some insight into what resource got stuck when it gives up waiting for something after 500ms.

What happens instead? Failure without insight into what resource is being problematic.

PS. I own https://songsear.ch and it works in all browsers that I know of but if it helps the cause can I fiddle with that site, to some degree, to figure this out for the sake of puppeteer.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 17
  • Comments: 20 (2 by maintainers)

Most upvoted comments

I suppose an array of the remaining open network connections would at least enable the developer to eliminate certain possibilities but it could also lead to a lot of wild goose chases when none of those URLs are the cause.

You can track this with the request, requestfailed and requestfinished events.

class InflightRequests {
  constructor(page) {
    this._page = page;
    this._requests = new Set();
    this._onStarted = this._onStarted.bind(this);
    this._onFinished = this._onFinished.bind(this);
    this._page.on('request', this._onStarted);
    this._page.on('requestfinished', this._onFinished);
    this._page.on('requestfailed', this._onFinished);
  }

  _onStarted(request) { this._requests.add(request); }
  _onFinished(request) { this._requests.delete(request); }
 
  inflightRequests() { return Array.from(this._requests); }  

  dispose() {
    this._page.removeListener('request', this._onStarted);
    this._page.removeListener('requestfinished', this._onFinished);
    this._page.removeListener('requestfailed', this._onFinished);
  }
}

and use it later like this:

const tracker = new InflightRequests(page);
await page.goto(url).catch(e => {
  console.log('Navigation failed: ' + e.message);
  const inflight = tracker.inflightRequests();
  console.log(inflight.map(request => '  ' + request.url()).join('\n'));
});
tracker.dispose();

Hope this helps.

I have exactly the same problem, the thing is I don’t have this problem if I run puppeteer on Mac, but when I switch to docker (linux) then I have this issue. Both Mac and docker are using the same chrome version HeadlessChrome/66.0.3347.0

@jacobweber something like this might help, unless your sockjs-node calls are required for your page to load correctly:

      await page.setRequestInterception(true)

      page.on('request', req => {
        // disable webpack HMR, which breaks the 'networkidle0' setting
        if (req.url().endsWith('/__webpack_hmr')) {
          req.abort()
        } else {
          req.continue()
        }
      })

I’m getting this Navigation Timeout Exceeded error seemingly randomly. Even using networkidle2. Using 1.0 in docker.

I request we re-open this.

You can track this with the request, requestfailed and requestfinished events.

said @aslushnikov

In https://github.com/peterbe/minimalcss/pull/199 we tried implementing a tracker so that we can extend the Navigation Timeout Exceeded: 30000ms exceeded error message with a list of URLs that got started but never finished. Even with that, and with upgrading to puppeteer 1.4.0, it still fails with the tracker not having any unfinished URLs.

I also tried logging every single possible event (that has to do with requests) on the Page object. And that too didn’t help. Still no insight into what request is exceeding the timeout.

My hunch is that it’s related to service workers. The service-worker set up the site I’m testing against is “stock create-react-app” style. Nothing fancy. I can try the same URLs by changing it to http://songsearch.local which is my local Nginx. When I do that, it always works. And since it’s not HTTPS the service-worker will be automatically disabled.

So, are there tools and techniques to track (and even disable) service workers?

Thanks @aslushnikov, in my case Webpack’s Hot Module Reload remained connected: http://localhost:8009/__webpack_hmr

My limited experience of Navigation Timeout Exceeded errors is that you can get them for a huge number of reasons. Some sites seem to have multiple open connections that even networkidle2 won’t allow for. If you go for the load event and test the same sites, this will tell you whether any given site has this characteristic. Also, timeout exceeded error will occur seemingly randomly where you are operating at the limit of your system resource limitations, whether that be in terms of your memory usage or network connections.