Fix GitHub Actions pwsh Not Found on Ubuntu
Zusammenfassung
Pixel shares a guide to GitHub Actions pwsh command not found errors on Ubuntu. It explains that shell lookup fails before a script starts, so there is no exit code, and covers common causes such as missing PowerShell Core, copied Windows shell settings, container differences, and custom shell commands.
DEV Community
GitHub Actions pwsh command not found on an Ubuntu runner
GitHub Actions pwsh command not found is raised while the runner is looking for the shell binary, which is before your script has been started and before any process could have exited. That ordering is the useful part: there is no exit code attached to this failure, so an answer that tells you to go and read one is describing a different problem. Shell resolution happens before the script file is written. A failure here means no process was started, so no exit code exists. What this error means A step that declares the PowerShell Core shell fails immediately, with a short line naming the command. Steps around it that use the default shell run normally, which makes the runner look selectively broken. On a GitHub hosted Ubuntu image this is rare because those images ship the shell. On a self hosted runner, a container image built in house or a runner in a minimal base image, it is the expected result of asking for a program that was never installed. ```Reconstructed from the FileNotFoundException message in WhichUtil.Which, actions/runner pwsh: command not found
Common causes
The runner image does not include PowerShell Core
The direct cause in almost every report. Self hosted machines, container images and minimal bases install what the build needs, and a shell nobody asked for at image build time is not there at job time.
The step was copied from a Windows job
A workflow that grew a Linux matrix leg keeps the shell declaration that made sense on Windows. The step is often small enough that the shell is not really needed at all.
The job runs in a container that differs from the host
A step running inside a container is looked up differently from one running on the host, and a shell present on the machine is not necessarily present in the image the job is using.
The shell string is custom and names a program that is absent
A shell value with arguments is parsed into a command and a format, and the command is looked up like any other. In our experience this version is harder to spot because the eye reads the whole string as configuration rather than as a program name.
How to fix it
Check for an exit code before anything else
- Look at the failing step for an exit status line.
- If there is one, this page is not your failure; the script started and something inside it was missing.
- If there is none and the line is just the command name, the runner could not find the shell.
Use the default shell when the script is small
Drop the shell declaration and translate the commands. On Linux the runner resolves the default by looking for one shell and falling back to another, so you do not need to name anything.
```.github/workflows/ci.yml
- name: Print the version
run: |
node -p "require('./package.json').version"
Install the shell in the image, not in the job Add it where the runner image is built so every job starts with it present. Installing it as a step costs time on every run and turns a clear failure into a network dependent one. Probe for the program and fail with a useful message Where you cannot control every runner, check for the program in an early step and say what is missing. A named assumption is easier to act on than a lookup failure in the middle of a matrix. - name: Preflight
run: |
command -v pwsh >/dev/null || {
echo "this job needs PowerShell Core on the runner"; exit 1; }
How to prevent it Keep the shell values in a workflow to programs the runner image is known to ship. Install shells at image build time, never as a workflow step. Probe for unusual programs in one preflight step rather than discovering them mid matrix. When adding a Linux leg to a Windows matrix, review every shell declaration. Where the message comes from, and what it rules out Before a run step executes, the runner has to decide which program will execute it. For a step that names one of the built in shells it looks that program up on the path, with a flag that says the lo...

Powered by Readybot.io