Skip to content

/flags/powershell/erroraction-stop-try-catch

PowerShell -ErrorAction Stop: why try/catch does not catch the error

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
PowerShell
command
any cmdlet or advanced function
flag
-ErrorAction (-ea)
default
Continue (from $ErrorActionPreference)

try { Get-Item missing.txt } catch { ... } does not run the catch block, because most cmdlet errors are non-terminating: the cmdlet writes the error and carries on, and try only reacts to terminating errors. Add -ErrorAction Stop to the command (or set $ErrorActionPreference = 'Stop' for the whole script) to turn its errors into terminating ones that catch receives.

powershell
try {
    Get-Item -Path missing.txt -ErrorAction Stop
} catch {
    Write-Warning "Failed: $($_.Exception.Message)"
}

Non-terminating vs terminating

powershell
try { Get-Item missing.txt 2>$null; 'try block went on after the error' } catch { 'caught' }
try { Get-Item missing.txt -ErrorAction Stop; 'not printed' } catch { "caught: $($_.Exception.GetType().Name)" }
$ErrorActionPreference = 'Stop'
try { Get-Item missing.txt } catch { 'caught with $ErrorActionPreference = Stop' }

Output

try block went on after the error
caught: ItemNotFoundException
caught with $ErrorActionPreference = Stop

-ErrorAction values

ValueEffect
Continue (default)print the error, continue with the next item and command
Stopturn the error into a terminating one; try/catch and trap see it
SilentlyContinuedo not print; the error is still added to $Error
Ignoredo not print and do not add to $Error (not allowed in $ErrorActionPreference)
Inquireask the user what to do (fails in non-interactive sessions)
Break (PowerShell 7.1+)enter the debugger

Useful parts of the error record

powershell
try { Get-Item missing.txt -ErrorAction Stop }
catch {
    'Type:     ' + $_.Exception.GetType().FullName
    'Id:       ' + $_.FullyQualifiedErrorId
    'Category: ' + $_.CategoryInfo.Category
}

Output

Type:     System.Management.Automation.ItemNotFoundException
Id:       PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Category: ObjectNotFound

Catch a specific type with catch [System.Management.Automation.ItemNotFoundException] { ... } before a general catch { ... }.

When to use it

Add -ErrorAction Stop to every command inside a try block whose failure should change what the script does next: a file that must exist, a connection that must succeed, a user that must be found before you modify it. Without it, the script prints red text, carries on with empty variables, and fails later with a less useful message such as You cannot call a method on a null-valued expression.

Per item or all at once

powershell
Set-Content present.txt 'x'
'--- one try around the whole command:'
try { Get-Item absent1.txt, present.txt -ErrorAction Stop | ForEach-Object Name } catch { 'stopped at the first error' }
'--- one try per item:'
foreach ($f in 'absent2.txt', 'present.txt') {
    try { (Get-Item $f -ErrorAction Stop).Name } catch { "skipped $f" } finally { "done $f" }
}
'--- collect errors and continue:'
Get-Item absent3.txt, present.txt -ErrorAction SilentlyContinue -ErrorVariable failed | ForEach-Object Name
'errors collected: ' + $failed.Count

Output

--- one try around the whole command:
stopped at the first error
--- one try per item:
skipped absent2.txt
done absent2.txt
present.txt
done present.txt
--- collect errors and continue:
present.txt
errors collected: 1

The finally block runs whether or not an error occurred, which makes it the place for cleanup such as Disconnect-ExchangeOnline or closing a file.

Scope of the preference variable

-ErrorAction affects one command. $ErrorActionPreference affects every command in the current scope and in the scopes it creates, such as functions and script blocks you call. A function that sets it changes only its own behaviour.

Pitfalls

  • 2>$null is not error handling. It hides the message but the error is still non-terminating and still added to $Error.
  • Catching everything. A bare catch also catches typing mistakes in the try block. Print $_.Exception.Message and $_.InvocationInfo.PositionMessage while developing.
  • Exit codes. A script that ends inside catch without exit 1 returns 0 to the caller (scheduler or CI). Add an explicit exit with a non-zero code when the failure must be visible.

FAQ

Should I set $ErrorActionPreference = 'Stop' at the top of every script?

It is a common choice for automation, because any failed cmdlet then stops the script instead of letting it continue with missing data. Wrap the steps that may fail in try/catch so you control the message and the exit code.

Does -ErrorAction Stop stop the whole pipeline at the first failed item?

Yes. With Stop, the first error ends the command, so the remaining items are not processed. Put the try/catch inside a foreach loop to handle each item separately.

How do I collect errors without stopping?

Use -ErrorAction SilentlyContinue with -ErrorVariable name. The command processes every item, and the variable holds the error records to report afterwards.

Sources