0

This is a followup question to this one, which resolves a missing definition of TimeoutError in my puppeteer code. Thing is, I want to use puppeteer-extra, and despite being a lightweight wrapper for puppeteer it seems to be causing a difficulty in getting hold of TimeoutError. Here's an SSCCE that should demonstrate the problem; I get TypeError: Right-hand side of 'instanceof' is not an object. My package.json states version 23.7.1 (I have no idea what version of puppeteer-extra I'm running as I don't know where to look).

const puppeteer = require("puppeteer-extra");

let browser;
(async () => {
  const stealthPlugin = require('puppeteer-extra-plugin-stealth');
  puppeteer.use(stealthPlugin());

  browser = await puppeteer.launch();
  const [page] = await browser.pages();

  try {
    await page.goto("https://www.example.com", {timeout: 1}); // short timeout to force a throw
  }
  catch (err) {
    if (err instanceof puppeteer.TimeoutError) {
      console.log("caught timeout error", err);
    }
    else {
      console.log("caught non-timeout error", err);
    }
  }
})()
  .catch(err => console.log(err))
  .finally(() => browser?.close());
  

(I'm using console.log() instead of console.error() because my client code can't get hold of anything in the error stream)

Edit: in response to a comment, here is the entire content of my package.json file -- I regret that it says nothing about puppeteer-extra :(

{
  "name": "puppeteer-project",
  "version": "1.0.0",
  "description": "Puppeteer Project",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "puppeteer": "^23.7.1"
  }
}

Edit 2: have found what seems to be the version numbers for various puppeteer-extra components:

puppeteer-extra: 3.3.6
puppeteer-extra-plugin: 3.2.3
puppeteer-extra-plugin-stealth: 2.11.2
puppeteer-extra-plugin-user-data-dir: 2.4.1
puppeteer-extra-plugin-user-preferences: also 2.4.1

Edit 3: in an attempt to solve this have modified the code in answer 1 below so that instead of only importing TimeoutError we import all of puppeteer (note, the puppeteer version number is different from that in answer 1):

const pupbasic = require("puppeteer"); // ^23.7.1
const puppeteer = require("puppeteer-extra"); // ^3.3.6
const stealthPlugin = require("puppeteer-extra-plugin-stealth"); // ^2.11.2
puppeteer.use(stealthPlugin());

let browser;
(async () => {

  browser = await puppeteer.launch();
  const [page] = await browser.pages();

  try {
    await page.goto("https://www.example.com", {timeout: 1}); // short timeout to force a throw
  }
  catch (err) {
    if (err instanceof pupbasic.errors.TimeoutError) {
      console.log("caught timeout error", err);
    }
    else {
      console.log("caught non-timeout error", err);
    }
  }
})()
  .catch(err => console.log(err))
  .finally(() => browser?.close());

...and once again I get the TypeError: Cannot read properties of undefined (reading 'TimeoutError') error. I may be completely lacking in javascript experience (and unable to find the relevant source files to actually start grubbing through them) but it really escapes me why I can import TimeoutError and have it be recognised by the system (setting aside for a moment the issue that it's not working correctly -- see comment below answer 1), but can't import standard puppeteer and then successfully get inside it. Is there some syntax that I'm missing here?

In case it makes a difference, I actually seem to have two versions of puppeteer on my system. The package.json inside my project's folder says 23.7.1, but the one inside node-modules/puppeteer, in my home folder, says 23.9.0. I assume I'm running the latter, despite what the project's package.json says??? Does this possibly make a difference?

Grateful thanks for any help resolving this! I really am stumbling around in the dark here.

5
  • Based on the linked question, can you import the errors object from the puppeteer package? Is it a version issue? Commented Jun 30 at 1:34
  • "(I have no idea what version of puppeteer-extra I'm running as I don't know where to look)." Check package.json for a line like "puppeteer-extra": "^3.3.6",. Can't hurt to also provide the version for puppeteer-extra-plugin-stealth so we have the complete picture. Commented Jun 30 at 1:41
  • @ggorlen see edit above. I'll be happy to provide further version info if you guys can tell me where to look -- I do apologise for my extreme lack of experience here... Commented Jun 30 at 6:26
  • Did you install those packages globally npm i -g puppeteer-extra? I'd just run npm i puppeteer-extra puppeteer-extra-plugin-stealth to install them in the project folder, then share that package.json (this will install the latest versions of both packages, which is a fair assumption). Commented Jun 30 at 6:31
  • 1
    @ggorlen OK, I've found puppeteer-extra in node_modules, at the top level of my user home folder. I'm guessing that means I did a global install but I really have no idea; it was late November last year and I simply followed the instructions <wherever they were>. That puppeteer-extra/package.json states version 3.3.6, and it has the following siblings: puppeteer-extra-plugin which seems to be vsn 3.2.3, puppeteer-extra-plugin-stealth (vsn 2.11.2), puppeteer-extra-plugin-user-data-dir (vsn 2.4.1) and puppeteer-extra-plugin-user-preferences (vsn also 2.4.1). Commented Jun 30 at 7:09

1 Answer 1

1

I don't see offhand that puppeteer-extra 3.3.6 exports TimeoutError, but you can import it from vanilla Puppeteer, installed alongside puppeteer-extra:

const {TimeoutError} = require("puppeteer"); // ^24.11.1
const puppeteer = require("puppeteer-extra"); // ^3.3.6
const stealthPlugin = require("puppeteer-extra-plugin-stealth"); // ^2.11.2
puppeteer.use(stealthPlugin());

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();

  try {
    await page.goto("https://www.example.com", {timeout: 1}); // short timeout to force a throw
  }
  catch (err) {
    if (err instanceof TimeoutError) {
      console.error("caught timeout error", err);
    }
    else {
      console.error("caught non-timeout error", err);
    }
  }
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

Or use the following if you want a namespace:

const vanillaPuppeteer = require("puppeteer");

console.log(vanillaPuppeteer.TimeoutError);

A workaround that doesn't involve adding an import is to use if (error.name === "TimeoutError"), but this isn't type safe. This may be suitable for a small script though.

Sign up to request clarification or add additional context in comments.

9 Comments

We have made progress :) Now I don't get the complaint that TimeoutError doesn't exist...but the timeout clearly isn't being recognised as one, because the output is caught non-timeout error TimeoutError: Navigation timeout of 1 ms exceeded
Weird, this code works fine for me. caught timeout error TimeoutError: Navigation timeout of 1 ms exceeded logs, as expected.
Apologies for the delay, I am slammed during the week currently so only get to work on this in the weekends, or tiny scraps of time. Have made a third edit to the OP in the hopes of being able to get my system to produce a correct result. Yes, your if (error.name === "TimeoutError") does work, but I'd really rather do something type safe if possible.
TimeoutError is not nested inside .errors, it's top-level. So if you want to use const pupbasic = require("puppeteer");, then you'd only do one level of namespacing when you use it: pupbasic.TimeoutError, not pupbasic.errors.TimeoutError. I confirmed this works as expected on my machine.
Many thanks -- this runs, but once again goes down the incorrect path. OK, I'm desperate. I wanted to not run the risk of updating my puppeteer install, just in case it breaks something, but I'll try that. Do you happen to know, is the puppeteer installation only the files in the node_modules directory in my home folder? i.e. if I take a copy of this directory beforehand, is that all I'd need to move back if something does break?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.