PowerShell exit code not propagated (ErrorActionPreference) in CI
By Daniel Zoghalchali·Latchkey
A PowerShell step reported success even though a command inside it failed. By default PowerShell does not stop on native-command failures, and $LASTEXITCODE may not become the step exit code.
What this error means
The job is green but a tool inside the step clearly errored. There is no exception; the failing native command returned non-zero and PowerShell ignored it. Deterministic given the script.
powershell
# step is GREEN, yet the test run failed:
npm test # exits 1
Write-Host 'done' # runs anyway, step exits 0
Diagnose it: which runtime is actually on PATH?
Runners ship multiple versions of most runtimes and select one through a version manager. When a setup action and a version file disagree, the resulting error is about your code rather than the version.
Terminal
which -a <runtime>
<runtime> --version
echo "PATH=$PATH" | tr ":" "\n" | head -20
# does a version file in the repo disagree with the workflow?
cat .tool-versions .nvmrc .ruby-version .python-version 2>/dev/null
Common causes
Native-command failures do not throw
PowerShell only honors ErrorActionPreference for cmdlets, not for external .exe failures. A non-zero exit from a native tool does not raise and does not stop the script.
The last expression overwrote $LASTEXITCODE
A trailing Write-Host or successful command resets the effective exit code, masking the earlier failure from the runner.
How to fix it
Check $LASTEXITCODE after native commands
Explicitly fail the step when a native command returns non-zero.
powershell
npm test
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Enable strict failure handling
Stop on cmdlet errors and treat any pipeline failure as fatal at the top of the script.
powershell
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
# for native commands, still guard $LASTEXITCODE explicitly
How to prevent it
Set $ErrorActionPreference = Stop and assert $LASTEXITCODE after every native command so failures fail the step instead of being swallowed.
Frequently asked questions
What causes PowerShell exit code not propagated (ErrorActionPreference) in CI?
There are 2 common causes: native-command failures do not throw and the last expression overwrote $lastexitcode. PowerShell only honors ErrorActionPreference for cmdlets, not for external .exe failures.
How do I fix PowerShell exit code not propagated (ErrorActionPreference) in CI?
There are 2 fixes depending on which cause you have: check $lastexitcode after native commands and enable strict failure handling. Work through them in order, since the first is the most common.
What does PowerShell exit code not propagated (ErrorActionPreference) in CI actually mean?
The job is green but a tool inside the step clearly errored.
How do I stop PowerShell exit code not propagated (ErrorActionPreference) in CI happening again?
Set $ErrorActionPreference = Stop and assert $LASTEXITCODE after every native command so failures fail the step instead of being swallowed.