Skip to content
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

Installation fails on Apple Silicon / M1 #6622

Closed
stnwk opened this issue Nov 24, 2020 · 59 comments · Fixed by #7099
Closed

Installation fails on Apple Silicon / M1 #6622

stnwk opened this issue Nov 24, 2020 · 59 comments · Fixed by #7099

Comments

@stnwk
Copy link

stnwk commented Nov 24, 2020

Steps to reproduce

  • Puppeteer version: 5.5.0
  • Platform / OS version: macOS Big Sur 11.0.1 (Apple Silicon)
  • Node.js version: 15.2.1

What steps will reproduce the problem?

  1. Install puppeteer using yarn or npm

What is the expected result?
puppeteer gets installed

What happens instead?
Installation fails.

error path-to-project/node_modules/puppeteer: Command failed.
Exit code: 1
Command: node install.js
Arguments:
Directory: path-to-project/node_modules/puppeteer
Output:
The chromium binary is not available for arm64:
If you are on Ubuntu, you can install with:

 apt-get install chromium-browser

path-to-project/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserFetcher.js:112
            throw new Error();
            ^
@gijo-varghese
Copy link

So there is no way to run Puppeteer in M1 Mac?

@stnwk did you find any solution?

@joshuajung
Copy link

I got Puppeteer to work just fine on M1 by providing the Chromium binary myself from https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Mac/818858/ (it's the Intel build, but runs fine via Rosetta 2 – get chrome-mac.zip). You can point Puppeteer to it using the executablePath option in .launch(). Note that you need to point to /Contents/MacOS/Chromium inside the app bunde.

Due to the bug described in #6634, I also had to make a minor code adjustment in the launcher, see joshuajung@7987b91.

@steida
Copy link

steida commented Dec 21, 2020

@gijo-varghese It works OOTB with Rosetta. I did not have to change anything.

@gijo-varghese
Copy link

@steida how did you install Puppeteer via Rosetta?

@steida
Copy link

steida commented Dec 22, 2020

@gijo-varghese Nothing special, Node.js 12 and 14 is installed via nvm. The problem is Node 15, which is arm compiled and then it requires Chromium ARM.

@joshuajung
Copy link

Yup, what @steida says above. As long as you are running Node (or your whole shell) via Rosetta, Puppeteer doesn't even notice it's on ARM and is happy.

Once you use an ARM Node however (>= 15, built on an ARM Mac), you run into #6634 and need to supply Chromium yourself. Chromium can still be an Intel build, but Puppeteer will struggle to install and/or find it. For a workaround, see #6622 (comment).

@bbernstein
Copy link

I'm using node v12 running terminal (also tried iterm) but running in Rosetta 2. arch returns i386. Then create a fresh new npm project and tried installing npm install puppeteer and it failed with the same error. I'm curious how it is working for others. Perhaps something related to how nvm or node were installed? Maybe we need to do some more exploring to see why is succeeds for some but not others.

@bbernstein
Copy link

I found the issue I was having and hopefully it can help others. Since this is day 1 on the m1, I installed as brew as arm in /opt/homebrew and set up /etc/path and .zshrc to use that dir for all the brew-installed things. Once you need to go back to using i86, you need to update /etc/path to use /usr/local/bin again and fix the references in .zshrc. I then installed nvm from the i86 version of homebrew and now it's working correctly using Rosetta 2. Hope that helps others get this working.

@SirasornT
Copy link

Hello @joshuajung . I am downloaded the chrome-mac.zip from the link you have provided and unzipped it to the root of my project. Then I did

import chromium from "chrome-aws-lambda";

module.exports = (async function () {
  const browser = await chromium.puppeteer.launch({
    args: [...chromium.args, "--hide-scrollbars", "--disable-web-security"],
    defaultViewport: chromium.defaultViewport,
    executablePath: "../../chrome-mac/Chromium.app/Contents/MacOS/Chromium",
    headless: true,
    ignoreHTTPSErrors: true,
  });

  return browser;
})();

But this gets me an error Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT.
Am I missing something here?

@joshuajung
Copy link

joshuajung commented Jan 11, 2021

@SirasornT

But this gets me an error Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT.

Am I missing something here?

You probably didn't patch Launcher.ts as described in joshuajung@7987b91 yet (still required until the fix for #6634 is released).

@bwarne
Copy link

bwarne commented Jan 14, 2021

Thanks for all the helpful tips in the previous posts. For anyone else looking for more explicit instructions, this is what finally got things working for me:

Create a "Rosetta Terminal" (https://osxdaily.com/2020/11/18/how-run-homebrew-x86-terminal-apple-silicon-mac/) and install brew, node and yarn in this new terminal.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install node
npm install -g yarn
yarn

@iancdavis
Copy link

I'm having the same issue on a Raspberry Pi4 (also has arm64 chip).

Found this workaround (https://samiprogramming.medium.com/puppeteer-on-raspbian-nodejs-3425ccea470e) when running the 32bit os, but it fails when running the 64bit Raspian beta.

Managed to get puppeteer installed by using PUPPETEER_SKIP_CHROMIUM_DOWNLOAD, but still get this error,

(node:17769) UnhandledPromiseRejectionWarning: Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT

Puppeteer is using the path "/usr/bin/chromium-browser", but my launch config is "executablePath: '/usr/bin/chromium'"

I know this is a Mac thread, but this discussion is the closest I've seen to my issue. Thanks!

@Lxstr
Copy link

Lxstr commented Feb 5, 2021

This is what I've tried (after many circles) and installs but still doesn't run
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 npm i puppeteer

Then find this file
node_modules/puppeteer/lib/esm/puppeteer/node/Launcher.js

Replace line 54 with
chromeExecutable = "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
(or any other)

See
#6641

@Lxstr
Copy link

Lxstr commented Feb 5, 2021

It finally works when I follow the variable down the line and replace line 79 or BroswerRunner.js

    this.proc = childProcess.spawn("/Applications/Chromium.app/Contents/MacOS/Chromium", this._processArguments, 

@steida
Copy link

steida commented Feb 24, 2021

Just curious whether this is planned to be ever fixed.

@nezaboravi
Copy link

why is this closed? It does not work today

@chetbox
Copy link

chetbox commented Mar 1, 2021

The solution for me using Chromium from Homebrew was:

brew install chromium
`which chromium`

You will get a security warning. Close it and go to System Preferences > Security & Privacy > General and click Open anyway.

Quit Chromium.

To ~/.zshrc add:

export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=`which chromium`

Then restart your terminal.

Edit: Thanks to @gwuah for clarifying that you may need to upgrade Puppeteer. puppeteer: ^9.1.1 should work.

@neilyio
Copy link

neilyio commented Mar 1, 2021

A combination of steps from @chetbox and @Lxstr just worked for me. It involved creating a fork of puppeteer and changing a single line of source code. Here's the exact steps for my project, in ~/Documents/my-project, where trying to install puppeteer gives me the following error:

The chromium binary is not available for arm64
  1. In Terminal, run export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true. This will allow puppeteer to install.
  2. npm install puppeteer. It will skip trying to download chromium and install correctly.
  3. At this point, trying to run puppeteer (for me, using the command npm run test) gives the following error:
Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT
  1. brew install chromium. Run which chromium to make sure it installed properly, it should output the path to the new Chromium executable.

  2. In Terminal, run:

export PUPPETEER_EXECUTABLE_PATH=`which chromium`

Running export PUPPETEER_EXECUTABLE_PATH did not work for me on its own. This is because puppeteer currently hard-codes /usr/bin/chromium-browser in Launcher.ts (compiled to Launched.js) if it detects you're on arm64. It doesn't even bother to check the environment variables.

This is where I needed to fork puppeteer. I cloned it to ~/Documents/puppeteer and created a new branch.

  1. Open ~/Documents/puppeteer/src/node/Launcher.ts. Line 180 shows:
      if (os.arch() === 'arm64') {
        chromeExecutable = '/usr/bin/chromium-browser';
     } ....

This is where problem is with the hard-coded path. It immediately assumes where chromium-browser is located, which (at least for me) is not the case with Homebrew installs on Big Sur. The else part of this statement is where it checks your environment variables for configuration (like PUPPETEER_EXECUTABLE_PATH), but it never gets there if you're on arm64.

By skipping this os.arch() === 'arm64' check, we force puppeteer to look for the environment variables. I just changed line 180 to below:

      if (false) {
        chromeExecutable = '/usr/bin/chromium-browser';
     } ....

Now we need to link our "forked" puppeteer to our original project. First install puppeteer dependencies...

  1. Still in ~/Documents/puppeteer, run npm install to install everything puppeteer needs. Make sure your export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true is still set.
  2. npm run tsc to use the script in puppeteer's package.json to compile the TypeScript. You need recompile anytime you make a change to the source code in ~/Documents/puppeteer.
  3. npm link to create a global npm "symlink" to your ~/Documents/puppeteer.
  4. Change directory back to your main project, for me it's ~/Documents/my-project.
  5. npm link puppeteer to point my-project to your forked version of puppeteer.

npm run test again, and everything should work! As @chetbox suggested, you might add these to your ~/.zshrc~ to make sure your environment variables are set correctly when you re-open Terminal:

export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=`which chromium`

Hopefully this helps someone else from spending the many hours that I did trying to get this to work. This seems like it would be a pretty simple fix in puppeteer itself, so hopefully we get a real fix in a release soon. For anyone else that can't wait for a release to run their tests, I hope this is a viable option without having to change anything in your own project.

@peasey
Copy link

peasey commented Mar 7, 2021

Following on from the great tips above, you can pass the executablePath as an option to puppeteer.launch(), i.e.

const browser = await puppeteer.launch({
    executablePath: '/opt/homebrew/bin/chromium',
})

This saved me from having to do the fork/code change steps (step 6 onwards).

domoritz added a commit to domoritz/puppeteer that referenced this issue Mar 22, 2021
Same as puppeteer#6914 but with a different commit message.

With this change, we don't need to patch puppeteer on M1. See puppeteer#6622.
@bedney
Copy link

bedney commented Jun 15, 2022

The solution for me using Chromium from Homebrew was:

brew install chromium
`which chromium`

You will get a security warning. Close it and go to System Preferences > Security & Privacy > General and click Open anyway.

As of Big Sur 11.6.7, the control panel has changed. If you're using the standard Apple Terminal, you should be good to go. But who uses that? :-) I'm using iTerm. Here's what worked for me:

  1. Quit iTerm
  2. Go into System Preferences -> Security & Privacy
  3. Scroll down to Developer Tools and click4.
  4. You'll see the standard Apple Terminal listed in the list of apps “Allow the apps below to run software locally that does not meet the system’s security policy”.
  5. Add iTerm to that list.
  6. Restart iTerm

@ReDrUm
Copy link

ReDrUm commented Jun 21, 2022

Can anyone share a working Dockerfile using PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM?

I'm building on an M1 using docker buildx build --push --platform linux/arm64 ... and i've tried both strategies below, but both error out with:

The chromium binary is not available for arm64.
...
Failed to set up Chromium r1002410! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download.

FROM node:16.15.1-bullseye-slim

RUN apt-get update && apt-get install --no-install-recommends -yq dumb-init \
  # Install Chromium dependencies, necessary for running Puppeteer
  # Consult the Debian dependencies list for an updates when bumping Puppeteer or base images:
  # https://developers.google.com/web/tools/puppeteer/troubleshooting#chrome_headless_doesnt_launch_on_unix
  ca-certificates fonts-liberation libayatana-appindicator3-1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 \
  libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 \
  libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 \
  libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils \
  && apt-get clean && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*

# Attempt 1
ENV PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM true
RUN yarn global add puppeteer@14.4.1

# Attempt 2
RUN export PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM=true && yarn global add puppeteer@14.4.1

The expected arm64 build for 1002410 does exist here. It looks like puppeteer/lib/cjs/puppeteer/node/install.js doesn't consider thePUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM variable at all, even under 14.x which is supposed to support Apple Silicon 🤷‍♂️

Does anyone have this working with the new native binaries? Or, am I misinterpreting the point of that env var and it's only for running natively on an M1 mac directly rather than within a Linux based docker file?

@surajsharmadev
Copy link

surajsharmadev commented Jun 21, 2022

To delete the quarantine attribute:
xattr -d com.apple.quarantine /Applications/Chromium.app

@alannesta
Copy link

set PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM to true works for me (puppeteer@14.1.2).
I like the fact that I don't have to install chromium globally via brew, which makes it harder to manage

@7rulnik
Copy link
Contributor

7rulnik commented Jul 22, 2022

@ReDrUm you should not use PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM in docker. This flag for MacOS ARM. In docker, you have Linux so you need chromium for Linux.

@LuisPaGarcia
Copy link

I had this error message:

...
/Users/usern_name/path_to_repo/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserRunner.js:193
            reject(new Error([
                   ^

Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT


TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
...

I solved this problem by doing this:

  1. Installed Chromium via brew
$ brew install chromium
  1. Know the path location of the Chromium installation.
$ which chromium
/opt/homebrew/bin/chromium
  1. Search into the node_modules for this string: /usr/bin/chromium-browser. This is hardcoded for the 'arm64' processors in the Puppeteer code.
  2. Replace every usage of /usr/bin/chromium-browser for the one that which chromium prints.
  3. In my case I replaced /usr/bin/chromium-browser by /opt/homebrew/bin/chromium

Worked for the puppeteer@5.5.0 version, using a Macbook Pro M1 Max.

@nwpray
Copy link

nwpray commented Jan 24, 2023

Another solution that does not require rebuilding the puppeteer project is to use
Patch Package

I just replace this in the Launcher.js files:

 if (os.arch() === 'arm64') {
  chromeExecutable = '/usr/bin/chromium-browser';
 }

with:

 if (os.arch() === 'arm64') {
   chromeExecutable = process.env.PUPPETEER_EXECUTABLE_PATH || '/usr/bin/chromium-browser';
 }

Here are the paths to the launcher files in my node_modules as of now:
node_modules/puppeteer/lib/esm/puppeteer/node/Launcher.js
node_modules/puppeteer/lib/cjs/puppeteer/node/Launcher.js

After that you can run npx patch-package puppeteer in the root of you project and it will create a diff patch for you in the projects ./patches directory.

If you include a postinstall npm script in you package.json

{
  ...
  "postinstall": "npx patch-package",
  ...
}

This will automatically apply with npm installs. This should make a commit-able change that you can push to your repo. Now anyone with an M1 will just need to add the env vars specified above to your shell rc file and make sure you installed chromium locally and you should be up and going.

brew install chromium
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=`which chromium`

It is worth noting that this patch will only work as long as it does not conflict with what the maintainers have changed in future versions. It will tell you when the patch fails to apply in the future and you will have to go fix it yourself again manually.

@sarink
Copy link

sarink commented Feb 23, 2023

Why is this issue closed? Puppeteer still doesn't work on an M1... (v19.6.3)

Running node node_modules/puppeteer/install.js does correctly install a chromium binary to the ~/.cache/puppeteer dir, but if you try to execute it, it returns: Bad CPU type in executable

@phcoliveira
Copy link

Why is this issue closed? Puppeteer still doesn't work on an M1... (v19.6.3)

Running node node_modules/puppeteer/install.js does correctly install a chromium binary to the ~/.cache/puppeteer dir, but if you try to execute it, it returns: Bad CPU type in executable

If you can, move to Playwright. You won't be looking back.

dassencio added a commit to dassencio/blog that referenced this issue Feb 28, 2023
This commit makes screenshot tests work on macOS running on Apple silicon,
but adds Chromium as an external dependency for running them.

See puppeteer/puppeteer#6622 for more details.
dassencio added a commit to dassencio/blog that referenced this issue Feb 28, 2023
This commit makes screenshot tests work on macOS running on Apple silicon at
the cost of adding Chromium as an external dependency.

See puppeteer/puppeteer#6622 for more details.
@rvladynskyi
Copy link

Just follow the article. This is simple fix
https://broddin.be/2022/09/19/fixing-the-chromium-binary-is-not-available-for-arm64/

@jmealo
Copy link

jmealo commented Apr 27, 2023

This is even more complicated if you're trying to support local and Docker workflows multi-arch.

@chrisallick
Copy link

brew install chromium --no-quarantine

I found the above line on reddit. So take with a grain of salt, but this was necessary to get which chromium to work.

@sbassalian
Copy link

Mac OS

Here is my working solution using puppeteer's native chromium instead of installing your own:

  1. Uninstall puppeteer
  2. Open native terminal
  3. cd repo
  4. enter arch and see if it returns arm64
  5. enter nvm install stable
  6. enter nvm use stable
  7. verify installation by entering node -e 'console.log(process.arch)' and see if it returns arm64
  8. enter npm i puppeteer
  9. enter node node_modules/puppeteer/install.mjs (or node node_modules/puppeteer/install.js -- depending on your node modules)
  10. it should work 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.