Puppeteer: Missing stack trace on timeout

Created on 25 Sep 2017  路  3Comments  路  Source: puppeteer/puppeteer

Steps to reproduce

  • Puppeteer version: 0.10.1
  • Platform / OS version: OSX

Running this code:

'use strict';

const puppeteer = require('puppeteer');

main().then(() => {
  console.log('Done');
});

async function main() {
  process.on('unhandledRejection', r => {
    console.error(r);
    process.exit(1);
  });

  const browser = await puppeteer.launch();

  const page = await browser.newPage();
  await page.goto('https://www.google.com/', {
    waitUntil: 'networkidle'
  });
  await page.waitForSelector('#i-dont-exist', {
    timeout: 500
  });
}

Will produce the stack trace:

Error: waiting failed: timeout 500ms exceeded
    at Timeout.WaitTask._timeoutTimer.setTimeout (/Users/iftachbar/work/impactlabs/scrapper/node_modules/puppeteer/lib/FrameManager.js:410:58)
    at ontimeout (timers.js:488:11)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:283:5)

Which makes it very hard to debug the case.
The intuitive track trace I would expect should include the line where I run page.waitForSelector().

Maybe there is another solution I'm not thinking about...

Most helpful comment

I solved it with a monkey patch. Not the best solution out there, but it's a must if you have a big system and you need to debug where the wait got an error:

async function catchTimeoutErrors(callback) {
  const error = new Error('Got timeout');
  try {
    return await callback();
  } catch (e) {
    if (e.stack.indexOf('Timeout.WaitTask._timeoutTimer.setTimeout') >= 0) {
      error.stack += '\nCaused by ' + e.stack;
      throw error;
    }
    throw e;
  }
}

async function patchPuppeteer() {
  const browser = await puppeteer.launch({
    headless: true
  });
  const page = await browser.newPage();
  const mainFrame = page.mainFrame();
  const originalWaitForFunction = mainFrame.__proto__.waitForFunction;
  mainFrame.__proto__.waitForFunction = function waitForFunction() {
    return catchTimeoutErrors(() => originalWaitForFunction.apply(this, arguments));
  };
  await browser.close();
}

Wrote it for version 0.10.1, didn't test it with 0.11.0 yet.

All 3 comments

FWIW, parent functions which set timeout callbacks are also excluded from stack trace:

'use strict';

main();

function main() {
  setTimeout(() => { throw new Error('Error in a timeout'); }, 500);
}
Error: Error in a timeout
    at Timeout.setTimeout [as _onTimeout] (test.js:6:28)
    at ontimeout (timers.js:469:11)
    at tryOnTimeout (timers.js:304:5)
    at Timer.listOnTimeout (timers.js:264:5)

I solved it with a monkey patch. Not the best solution out there, but it's a must if you have a big system and you need to debug where the wait got an error:

async function catchTimeoutErrors(callback) {
  const error = new Error('Got timeout');
  try {
    return await callback();
  } catch (e) {
    if (e.stack.indexOf('Timeout.WaitTask._timeoutTimer.setTimeout') >= 0) {
      error.stack += '\nCaused by ' + e.stack;
      throw error;
    }
    throw e;
  }
}

async function patchPuppeteer() {
  const browser = await puppeteer.launch({
    headless: true
  });
  const page = await browser.newPage();
  const mainFrame = page.mainFrame();
  const originalWaitForFunction = mainFrame.__proto__.waitForFunction;
  mainFrame.__proto__.waitForFunction = function waitForFunction() {
    return catchTimeoutErrors(() => originalWaitForFunction.apply(this, arguments));
  };
  await browser.close();
}

Wrote it for version 0.10.1, didn't test it with 0.11.0 yet.

@barnash there are multiple of places where puppeteer is asynchronous and where stack traces would be confusing.

The solution would be node.js collecting async stacktraces; all other solutions won't work good enough in general case.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ryanvincent29 picture ryanvincent29  路  3Comments

namma-geniee picture namma-geniee  路  3Comments

ebidel picture ebidel  路  3Comments

td0m picture td0m  路  3Comments

selfrefactor picture selfrefactor  路  3Comments