Repository navigation
Why do handled exceptions show in ErrorVariable? #3768
Copy link
Copy link
Open
Labels
Breaking-Changebreaking change that may affect usersbreaking change that may affect usersCommittee-ReviewedPS-Committee has reviewed this and made a decisionPS-Committee has reviewed this and made a decisionIssue-Enhancementthe issue is more of a feature request than a bugthe issue is more of a feature request than a bugIssue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aKeepOpenThe bot will ignore these and not auto-closeThe bot will ignore these and not auto-closeUp-for-GrabsUp-for-grabs issues are not high priorities, and may be opportunities for external contributorsUp-for-grabs issues are not high priorities, and may be opportunities for external contributorsWG-Enginecore PowerShell engine, interpreter, and runtimecore PowerShell engine, interpreter, and runtime
Description
When you use try/catch and handle an exception, it still shows up in the global $Error, and more importantly, in the ErrorVariable.
Is there any way to actually prevent handled exceptions from leaking into the ErrorVariable? Is there any way for a caller to determine that they are not, in fact, errors, but expected results that were dealt with by the function? That is, how does a caller distinguish the errors that matter?
Consider a simple example:
function Count-Parameters {
[CmdletBinding()]
param([Parameter(ValueFromRemainingArguments)]$Parameters)
try {
$Parameters.FasterMethod()
} catch {
$Parameters.Count
}
}
$Count = Count-Parameters # Everything is fine
$Count = Count-Parameters This One Has Four # Still fine
# But then my paranoid "best practice" fanatic does something like this:
$Count = Count-Parameters -ErrorVariable noCount
if(!$Count -and $NoCount) {
Write-Warning $noCount
}How can I stop the error variable from containing these things that I explicitly handled?
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Breaking-Changebreaking change that may affect usersbreaking change that may affect usersCommittee-ReviewedPS-Committee has reviewed this and made a decisionPS-Committee has reviewed this and made a decisionIssue-Enhancementthe issue is more of a feature request than a bugthe issue is more of a feature request than a bugIssue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aKeepOpenThe bot will ignore these and not auto-closeThe bot will ignore these and not auto-closeUp-for-GrabsUp-for-grabs issues are not high priorities, and may be opportunities for external contributorsUp-for-grabs issues are not high priorities, and may be opportunities for external contributorsWG-Enginecore PowerShell engine, interpreter, and runtimecore PowerShell engine, interpreter, and runtime
Activity
mklement0 commentedon May 12, 2017
Good catch (accidental pun).
Note that another quirk comes into play here:
-ErrorVariablealways returns a[System.Collections.ArrayList]instance, so that you'd have to useWrite-Warning $noCount[0], whereasWrite-Warning $noCountwould actually break, even though only 1 error is returned:-OutVariable,-InformationVariable, and-WarningVariableexhibit the same behavior - see #3773.BrucePay commentedon May 16, 2017
$Error was originally conceived as a running log of all errors that happened in your script, including exceptions that were caught or when ErrorAction was set to SilentlyContinue The goal was primarily for forensics analysis after your script had been run. (Note: this goal of recording all errors was muted somewhat by the introduction of -ErrorAction ignore where the error isn't written into the error variable.)
SteveL-MSFT commentedon May 16, 2017
Perhaps a non-breaking change is we could add a
IsHandledproperty to ErrorRecord to help filter?Jaykul commentedon May 16, 2017
Bruce Payette (@BrucePay) and the -ErrorVariable must mirror that? I mean, I'm ok with everything being in $Error ...
Steve Lee (@SteveL-MSFT) I guess that would at least give us a way ...
Right now I do not think there is a way to hide errors, and also tell whether or not a command was successful.
joeyaiello commentedon May 24, 2017
The @PowerShell/powershell-committee had a very interesting conversation around this, it's difficult to know which way we should go with this.
Could you explain in more detail why this is important to you? Is it simply that you're trying to drill the error variable down to zero as you test your code and try to catch all exceptions?
mklement0 commentedon May 25, 2017
I obviously can't speak for Joel Bennett (@Jaykul), but here's my 0.0178236 EUR (using today's exchange rate):
There are two conceivable scenarios (not mutually exclusive):
(a) I want to know if any non-terminating error occurred when the cmdlet / advanced function ran - in other words: if the cmdlet / advanced function fully succeeded.
(b) I want to examine the specific non-terminating errors emitted, if any, when the cmdlet / advanced function ran.
(a), even though it should be covered by automatic variable
$?, is currently not a reliable option (pet peeve alert), because:$?- see Automatic $? variable (success indicator) is reset to $true when a command is enclosed in parentheses - make $? only reflect command status, not expression status #3359Write-Errortypically still reports$?as true - see Write-Error in a function doesn't set automatic success variable $? to $False (doesn't set the execution status to indicate a non-terminating error) in the caller's scope #3629(b) is currently not a reliable option, because examining the
-ErrorVariable-assigned variable or the added-since-before-invocation$Errorentries may contain false positives in the form of intentionally caught exceptions that should be considered an implementation detail of the cmdlet / advanced function invoked - that's this issue's complaint.SteveL-MSFT commentedon May 31, 2017
@PowerShell/powershell-committee reviewed this (Bruce Payette (@BrucePay) was absent from discussion) and agreed this change where
-errorvariableonly contains unhandled errors makes sense5 remaining items
KirkMunro commentedon Aug 18, 2017
Michael Klement (@mklement0) That's really thin. If someone really wants to know if an error occurred when -ErrorAction Ignore is used, they should write their own script that doesn't use -ErrorAction Ignore. Give me a real world use case where someone would want to know if a benign error occurred in a command or script they invoked. You shouldn't care about that when you invoke a command, because at the moment you are invoking that command you are placing your trust that the author of that command will properly let you know if there was an error that you should care about. If you don't trust that, then you shouldn't be invoking that specific command.
The whole point of -ErrorAction Ignore is to suppress errors. Suppression is of little use for scripts invoked via S.M.A.PowerShell if the invoker has to ignore .HadErrors and check the Errors collection every time (which will be empty). In fact, I'd wager that there are probably many C# binaries out there where PowerShell is invoked from C# with S.M.A.PowerShell that are buggy right now because they rely on .HadErrors identifying whether or not there were actually errors.
I will log a separate issue for the .HadErrors/$? issue.
mklement0 commentedon Aug 18, 2017
Great, thanks.
Other than that, I don't see a disagreement, unless I misunderstood your original comment. You do not want
$?and.HadErrorsto reflect$Falseif-ErrorAction Ignoreis used, correct? I agree.Note that I was talking about SilentlyContinue, not Ignore, in the - definitely exotic - alternative scenario I described.
KirkMunro commentedon Aug 18, 2017
Michael Klement (@mklement0) Whoops, you're right, I misread your previous reply. We're on the same page then.
mklement0 commentedon Aug 18, 2017
Joel Bennett (@Jaykul): While I'm still unclear on what you were asking, perhaps I can clarify on my end:
Re logging in
$Error/-ErrorVariable:My concern fits into the larger issue of the existing, longstanding dichotomy with respect to how non-terminating vs. terminating errors must be handled - see Our Error Handling, Ourselves - time to fully understand and properly document PowerShell's error handling.
As Bruce Payette (@BrucePay) has pointed out,
-ErrorAction Ignorealready is a departure from the unconditionally-log-all-exceptions-in-$Errorbehavior, but is currently only available for non-terminating errors (e.g.,Get-Item /NoSuchPath -ErrorAction -Ignore).As stated,
-ErrorAction Ignorehas no effect on a (statement)-terminating error such asGet-Item -NoSuchParam -ErrorAction Ignore(a distinction that strikes me as problematic, especially that using the$ErrorActionPreferencepreference variable does apply to terminating errors, but it's probably way too late to change that).Here's what
-ErrorAction Ignorecombined with-ErrorVariablecurrently does:Your proposal at least in part asks for the analogous behavior with respect to handling terminating errors, which must be done with
Try/Catch.It is the in part aspect that I find problematic:
For symmetry, conceiving of
Try/Catchas the-ErrorAction Ignorecounterpart - or, more accurately, a superset of it - makes sense to me.If we only suppress filling the
-ErrorVariablevariable while continuing to log to$Error, we don't have that symmetry:Hence my suggestion to not only suppress assigning to the
-ErrorVariablevariable, but to also suppress logging to$Error.Re
$?/.HadErrors:Kirk Munro (@KirkMunro) then took a step back to bring up a conceptually related issue, arguing that
-ErrorAction Ignore- again: applicable to non-terminating errors only - should indicate success, given the explicitly signaled intent to ignore errors - similar to howTry/Catchcan be conceived of.My aside re
try { 1 / 0 } catch {}; $?was meant to show that in the terminating-error realm checking$?aftertry/catchis virtually pointless, because what$?is set to depends on whether thecatchblock happens to be empty ($False) or not (whatever statement happens to execute last in thecatchblock determines the value of$?).Taking another step back:
$?is problematic in other contexts too:Automatic $? variable is reset to $True when a command is enclosed in parentheses - make $? only reflect command status, not expression status
Write-Error in a function doesn't set $? to $False (doesn't set the execution status to indicate a non-terminating error) in the caller's scope
Jaykul commentedon Aug 20, 2017
I think we're in agreement.
My request is focused on ErrorVariable only because I was focused on error detection in a script.
That is, I wasn't concerned with
PowerShell.Invokeor any of the rest of this ;-)In general, I think it's useless to check
$Errorin scripts because it's persistent through a whole session, and you don't normally care about errors that happened before your code. Of course, there are lots of ways (not least-ErrorAction SilentlyContinue) that errors show up in$Errorand the user doesn't care, but since you're not normally using it, it doesn't matter the same way ErrorVariable does.For what it's worth, I would agree that exceptions that are handled in a catch could be left out of
$Erroras well asErrorVariable...microsoft-github-policy-service commentedon Jan 4, 2024
This issue has not had any activity in 6 months, if there is no further activity in 7 days, the issue will be closed automatically.
Activity in this case refers only to comments on the issue. If the issue is closed and you are the author, you can re-open the issue using the button below. Please add more information to be considered during retriage. If you are not the author but the issue is impacting you after it has been closed, please submit a new issue with updated details and a link to this issue and the original.
microsoft-github-policy-service commentedon Jan 4, 2024
This issue has not had any activity in 6 months, if there is no further activity in 7 days, the issue will be closed automatically.
Activity in this case refers only to comments on the issue. If the issue is closed and you are the author, you can re-open the issue using the button below. Please add more information to be considered during retriage. If you are not the author but the issue is impacting you after it has been closed, please submit a new issue with updated details and a link to this issue and the original.
MatejKafka commentedon May 19, 2024
Ryan Yates (@kilasuit) Please reopen, the issue is unresolved, but triaged and up-for-grabs.