--- name: powershell-error-handling description: "Use when: designing or reviewing PowerShell 7 error handling, try/catch/finally, terminating errors, ErrorAction, throw, Write-Error, ThrowTerminatingError, cleanup, retries, or error records." argument-hint: "Function or error path to improve" --- # PowerShell Error Handling Design predictable failures that callers can catch, inspect, and automate around. ## Workflow 1. Classify each failure as validation, expected operational failure, transient failure, cancellation, or programmer error. 2. Decide whether the function can continue processing later pipeline input. Use a non-terminating error only when continuing is meaningful; otherwise produce a terminating error. 3. Remember that `try/catch` catches terminating errors. Add `-ErrorAction Stop` to a command inside `try` when its normally non-terminating error must transfer control to `catch`. 4. Catch the narrowest useful exception type before general catches. Use the `ErrorRecord` in `$_` to preserve exception, category, target object, and stack information. 5. Recover only when the function can establish a valid result. Otherwise rethrow. Use a bare `throw` when no extra context is needed. To add context, construct a new exception with the original as its `InnerException` (for example, `throw [System.InvalidOperationException]::new("Failed to X", $_.Exception)`) or, in advanced functions, build a new `ErrorRecord` that wraps the original and pass it to `$PSCmdlet.ThrowTerminatingError()`. Never rethrow a string. 6. Put unconditional cleanup in `finally`. Make cleanup safe when initialization failed partway through. 7. Implement retries only for known transient operations. Bound attempts, use backoff, preserve cancellation, and throw the final error after exhaustion. 8. For advanced functions, use `$PSCmdlet.WriteError()` for non-terminating errors and `$PSCmdlet.ThrowTerminatingError()` when constructing a precise `ErrorRecord`. Do not emit error text to the success stream. 9. When `psmcp-builtin` is available, read changed scripts and use `parse_script` after editing. Recommend PSScriptAnalyzer as an optional local or CI check; address observed empty catches, broad preference changes, and lost error context. ## Rules - Do not set global `$ErrorActionPreference` in a reusable module. - Do not use `SilentlyContinue` unless absence is an expected branch and the result is checked. - Do not catch an error merely to print it and continue. - Do not use `exit` in a module function. - Do not put secrets, tokens, or full sensitive request bodies into error messages. - Preserve the distinction between terminating behavior and process exit codes. - In top-level scripts and CI entry points, it is acceptable to set `$ErrorActionPreference = 'Stop'` at script scope and to translate unhandled terminating errors into a non-zero `exit` code in an outermost `try/catch`. Do not apply these patterns inside functions exported from modules. ## Review Questions - Can callers catch the failure? - Is the target object identifiable without exposing sensitive data? - Does partial state require rollback or cleanup? - Can pipeline processing safely continue? - Does retrying risk duplicating a non-idempotent operation? ## Source - [about_Try_Catch_Finally](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_try_catch_finally)