15

In PowerShell, what is the difference between throw $ErrorMsg and $PScmdlet.ThrowTerminatingError($ErrorMsg)?

Are they same or different? If they are different which one is preferable?

Seth
  • 1,215
  • 15
  • 35
Samselvaprabu
  • 16,830
  • 32
  • 144
  • 230

1 Answers1

21

Throw creates a script-terminating (runspace-terminating) error, whereas $PScmdlet.ThrowTerminatingError() creates a statement-terminating error.

Note: These aren't official terms (the docs currently only vaguely reference terminating errors in the abstract, without scope), but they're useful for describing the de-facto behavior.

In short: By default,

  • a script-terminating error terminates the entire runspace by default, i.e., the running script and all its callers, with no further statements getting executed; in other words: unless such an error is caught or suppressed, it is fatal.

  • whereas a statement-terminating error terminates only the current statement (the function calling $PScmdlet.ThrowTerminatingError() and the statement it is a part of, which is often a pipeline), with execution continuing with the next statement by default.

    • They can be caught or suppressed in the same way that script-terminating errors can, but note that the common -ErrorAction parameter has no effect on them.

    • Conversely, you can promote them to script-terminating errors with $ErrorActionPreference = 'Stop', despite the docs claiming that $ErrorActionPreference pertains only to nonterminating errors, the 3rd error type (to which the -ErrorAction parameter exclusively applies).

For more information, see this (unofficial) overview of PowerShell's error handling.

As for guidance when to use which type of error:

  • There is little guidance as to when to use Throw in the about_Throw help topic; an example use case is given in which Throw is used to abort a function/script in the absence of a mandatory parameter, as an alternative to PowerShell's default behavior of prompting for it.

    • Just be aware that Throw, i.e., throwing a script-terminating error terminates the entire runspace (the running script and any of its callers), unless caught.
  • The Cmdlet Error Reporting article only discusses cmdlet-internal use with respect to when to report statement-terminating (called just "terminating" in the article) vs. nonterminating errors.

    • A concise summary of the article can be found in this answer.

Given the latter, you could argue that advanced functions - since they're like cmdlets - should at most report statement-terminating errors and that Throw (script-terminating errors) should be limited to scripts, but note that that contradicts the use of Throw to enforce mandatory parameters.

Perhaps the problematic distinction between script-terminating and statement-terminating errors is ultimately unintentional and perhaps the original intent was to only ever have script-terminating ones, which would explain why all the current documentation only ever talks about terminating errors in the abstract, without even mentioning the distinction.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I prefer to use script-terminating errors 99% of the time. That's simply how exceptions are supposed to work. I realize though, since it's a shell, there are some cases were it might make sense to just write to stderr instead, mostly in pipeline situations when processing multiple items. But to me, that's the "exception" - pun intended ;) – marsze Oct 23 '21 at 10:30
  • 1
    Agreed, @marsze. It wouldn't be officially admitted, but I still suspect that the _statement_-terminating errors were an accident, as also suggested by the fact that the docs never distinguishing between these two subtypes of terminating errors. Whatever the history may be, to me the elimination of statement-terminating errors in favor of only having script-terminating ones makes sense - but it's unlikely that this will happen. – mklement0 Oct 23 '21 at 14:27