Skip to content

Redirecting stderr / the error stream can trigger script-terminating errors #4002

Closed

Description

Closely related to #3996 and #11133

The current behavior of calling external programs without stderr redirection is being discussed in the linked issue.

Either way, simply adding 2>$null or 2>&1 - indeed, any redirection of stderr (2>...) - to a command shouldn't fundamentally change its error-handling behavior.

Note that when a host other than the console host is involved (e.g., when in the ISE or when remoting), the difference described below does not occur, but the behavior is fundamentally different (and presumably undesired - see #3996).

Note:

  • Even though the repro steps use external programs, PowerShell commands are equally affected (e.g., & { $ErrorActionPreference = 'stop'; Get-Item NosuchFile 2>$null } unexpectedly produces an error, whereas -ErrorAction SilentlyContinue would not).

  • Similarly, using 2> with an actual file as the target is also affected (e.g., & { $ErrorActionPreference = 'stop'; whoami badarg 2>stderr.txt } aborts, and stderr.txt is empty).

Steps to reproduce

On Unix, replace cmd /c with sh -c.

& { $ErrorActionPreference = 'stop'; cmd /c nosuch; $? }
& { $ErrorActionPreference = 'stop'; cmd /c nosuch 2>$null; $? }

Expected behavior

Both commands should fundamentally behave the same, which, based on the current default behavior in the console, is to not report an error, with stderr output passed through in the 1st command and stderr output getting suppressed in the other.

'nosuch' is not recognized as an internal or external command,
operable program or batch file.
False

Actual behavior

  • The 1st command behaves as expected.
'nosuch' is not recognized as an internal or external command,
operable program or batch file.
False
  • The 2nd command terminates the statement and outputs the first stderr line only in red (note that in Windows PowerShell you get the usual, full error output):
'nosuch' is not recognized as an internal or external command,

The 2nd half of the error message, operable program or batch file., is missing.

Presumably, this happens because:

  • as usual, each individual stderr line becomes its own [System.Management.Automation.ErrorRecord] instance,
  • and the very 1st line by itself triggers termination of the statement (in this particular case, the cmd error message happens to span 2 lines).

Note that any 2> redirection causes the symptom, such as 2>&1 or 2>err.txt.

Seemingly, the following happens:

  • Despite redirection of the error stream, the stderr lines are apparently still passing through it, as evidenced by them showing up in $Error afterwards.

  • With $ErrorActionPreference = 'stop' in effect, anything getting written to PowerShell's error stream instantly triggers a function/script-terminating error.

Again, note that without a redirection, stderr lines neither show up in $Error nor do they cause the script to be terminated based on $ErrorActionPreference = 'stop'.

Environment data

PowerShell Core v6.0.0-beta.4 on macOS 10.12.5
PowerShell Core v6.0.0-beta.4 on Ubuntu 16.04.2 LTS
PowerShell Core v6.0.0-beta.4 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Windows PowerShell v5.1.15063.413 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)

Activity

  1. PaulHigin commented on Jun 13, 2017

    @PaulHigin
    Contributor

    I am able to repro this. This does look like inconsistent behavior. If the default out-putter is configured then the error message is just displayed. But if error is redirected to a pipe then it goes through MshCommandRuntime processing and ErrorActionPreference is effective, and the stop exception is thrown.

    This is done here:
    https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/NativeCommandProcessor.cs#L634

  2. BurtHarris commented on Jun 14, 2017

    @BurtHarris

    I disagree w/ expected behavior. I don't think the expected behavior of 2>$null is documented anywhere. It was an intentional edge-case while I was searching for potential extensions to redirection syntax. You can find other similar cases, e.g.

    try {cmd /c whamo! 2>$()} catch { "Dang!" }
    
  3. BurtHarris commented on Jun 14, 2017

    @BurtHarris

    P.S. What Michael Klement (@mklement0) is referring to as "the 2nd half of the message" is not "missing", or if so then I found it... It's not coming from the native command, it's a PowerShell ErrorRecord that get's it's own slot.

    PS> $error.Clear()
    PS> cmd /c whamo! 2>$()
    PS> $error.Count
    2
    PS> $error[0]
    operable program or batch file.
    PS> $error[1]
    cmd : 'whamo!' is not recognized as an internal or external command,
    At line:1 char:1
    + cmd /c whamo! 2>$()
    + ~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: ('whamo!' is not...ternal command,:String) [], RemoteException
        + FullyQualifiedErrorId : NativeCommandError
    
  4. mklement0 commented on Jun 14, 2017

    @mklement0
    ContributorAuthor

    Burt Harris (@BurtHarris) I've revised the expected-behavior description in the original post in light of the discussion in the linked issue: if the consensus is that stderr output should never generate an error, then the expected behavior is as now described in the initial post.

    Yes, any 2> redirection triggers the symptom, presumably for the reasons Paul Higinbotham (@PaulHigin) states.

    Without $ErrorActionPreference = 'Stop' in the mix, you do indeed get all stderr lines recorded in $Error, as an error record each, but with $ErrorActionPreference = 'Stop', the 1st line triggers termination of the pipeline, so the 2nd line never gets recorded in $Error.

    I don't think the expected behavior of 2>$null is documented anywhere.

    Indeed, about_Redirection doesn't mention redirecting to $null, but if it does anything other than silently discarding the stream (as it does with the success stream, for instance), we have a problem - as evidenced by this issue.

    The unfortunate interaction with $ErrorActionPreference = 'Stop' is one thing, but the fact that output that you're asking to have suppressed is still getting recorded somewhere - in $Error - is absolutely counter-intuitive.

  5. added
    WG-Enginecore PowerShell engine, interpreter, and runtime
    Issue-BugIssue has been identified as a bug in the product
    on Jun 14, 2017
  6. zjrunner commented on Mar 11, 2019

    @zjrunner

    Where is this issue? I've been able to repro it across an upgrade of a build version and wonder if I'm missing something since this is such an old thread.

    repro: powershell v5.1.17763.316, OS 10.0.17763
    no-repro: powershell v5.1.16299.967, OS 10.0.16299

    Is the upgrade from 16299 to 17763 going to pull this in, and any projection of a fix? We've seen unreliability in our CI builds bailing out at odd times when they hit a machine with this newer powershell installed.

  7. changed the title [-]Adding a stderr redirection to an external-utility call changes error handling[/-] [+]Redirecting stderr / the error stream to $null can trigger a script-terminating error.[/+] on Nov 20, 2019
  8. changed the title [-]Redirecting stderr / the error stream to $null can trigger a script-terminating error.[/-] [+]Redirecting stderr / the error stream can trigger script-terminating errors[/+] on Nov 20, 2019
  9. joaoe commented on Nov 27, 2019

    @joaoe

    Hi.
    Let me chime in.

    I have a script which cheks if a python module is installed

    python -c "import blah" 2>$null
    if ($?) {
      # Run expensive installations
    }
    

    then I enabled strict error handling $ErrorActionPreference = "stop" and whenever that line runs (and the module is not setup), the whole script aborts instead of running the following steps.
    I tried also with python -c ... 2>&1 | out-null and the NativeCommandError is always there.
    This seems like a clear bug to me. If the error stream is being redirected to $null, that means that the user is explicitly ignoring any errors.
    So far, the only work around is to use try{} catch{}.

    Testcase

    Write-Host You should not see an error
    $ErrorActionPreference = "stop"
    python -c "import notfound_foobar" 2>$null
    Write-Host PASS
    
  10. andrewducker commented on Jan 23, 2020

    @andrewducker

    Have just hit this myself. Calling an exe and redirecting the errorstream to a file (it doesn't actually contain an error, just additional info), and had been happily using it for a year or two. I turned ErrorActionPreference to "Stop" globally, and suddenly it fails, despite there not being any actual errors.

  11. joeyaiello commented on Jul 13, 2020

    @joeyaiello
    Contributor

    Related to #3996, want to address similarly

  12. SteveL-MSFT commented on Jul 29, 2020

    @SteveL-MSFT
    Member

    We discussed this in the @PowerShell/powershell-committee and agreed this is a dupe of #3996

  13. added a commit that references this issue on Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-BugIssue has been identified as a bug in the productResolution-DuplicateThe issue is a duplicate.WG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions