Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exported functions not behaving correctly with -ErrorAction SilentlyContinue #409

Open
petervandivier opened this issue Jun 26, 2023 · 3 comments
Labels
bug This relates to a bug in the existing module. good first issue If you're new to the project (or to OSS in general) and you'd like to contribute, try this one. help wanted Anyone in the community is welcome to do this work

Comments

@petervandivier
Copy link

petervandivier commented Jun 26, 2023

Issue Details

Get-GitHubTeam -TeamName foo -ErrorAction SilentlyContinue returns all teams when team foo doesn't exist.

Steps to reproduce the issue

In the below example, I want to provision BTeam. I first check to see if that team exists so that I can create it if not. Instead, I end up modifying the settings for ATeam.

$Org = 'MyOrg'
New-GitHubTeam -Org $Org -TeamName ATeam

$team = Get-GitHubTeam -Org $Org -TeamName BTeam -ErrorAction SilentlyContinue 
if($null -eq $team){
    New-GitHubTeam -Org $Org -TeamName BTeam
} else {
    Set-GitHubTeam -Org $Org -TeamName BTeam 
}

Verbose logs showing the problem

N/A

Suggested solution to the issue

Immediately exit function Get-GitHubTeam when -TeamName is specified but no match is found.

Add a return at line 193.

if ($null -eq $team)
{
$message = "Team '$TeamName' not found"
Write-Log -Message $message -Level Error
throw $message
}

Requested Assignment

  • If possible, I would like to fix this.

Operating System

OsName               : Microsoft Windows 10 Enterprise
OsOperatingSystemSKU : EnterpriseEdition
OsArchitecture       : 64-bit
WindowsVersion       : 2009
WindowsBuildLabEx    : 19041.1.amd64fre.vb_release.191206-1406
OsLanguage           : en-US
OsMuiLanguages       : {en-US}

PowerShell Version

Name                           Value
----                           -----
PSVersion                      7.3.4
PSEdition                      Core
GitCommitId                    7.3.4
OS                             Microsoft Windows 10.0.19044
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Module Version

Running: 0.16.1
Installed: 0.16.1
@petervandivier petervandivier added bug This relates to a bug in the existing module. triage needed An issue that needs to be reviewed by a member of the team. labels Jun 26, 2023
petervandivier added a commit to petervandivier/PsGitHubOrgMap that referenced this issue Jun 27, 2023
@HowardWolosky HowardWolosky changed the title Get-GitHubTeam -TeamName NonExistentTeam -ea 0 returns all teams instead of empty set. Exported functions not behaving correctly with -ErrorAction SilentlyContinue Jun 28, 2023
@HowardWolosky HowardWolosky added help wanted Anyone in the community is welcome to do this work good first issue If you're new to the project (or to OSS in general) and you'd like to contribute, try this one. and removed triage needed An issue that needs to be reviewed by a member of the team. labels Jun 28, 2023
@HowardWolosky
Copy link
Member

Thanks for bringing this issue to my attention, @petervandivier!
I've had to dig into this deeper to understand what's going on, as it's quite confusing.

From the -ErrorAction documentation (emphasis mine):

Determines how the cmdlet responds to a non-terminating error from the command. This parameter works only when the command generates a non-terminating error, such as those from the Write-Error cmdlet.
...
The ErrorAction parameter has no effect on terminating errors (such as missing data, parameters that aren't valid, or insufficient permissions) that prevent a command from completing successfully.

From the throw documentation:

The throw keyword causes a terminating error.

Given that, the expectation would be that there would be no behavior difference when -ErrorAction SilentlyContinue is used on a function that fails with a throw vs without it, and yet it does:

function foo
{
    [CmdletBinding()]
    param()

    throw "error"
    write-host "I shouldn't see this"
}

# Just run it
foo

# results in this:
<#
Line |
   3 |      throw "error"
     |      ~~~~~~~~~~~~~
     | error
#>

# But if I run it with -ErrorAction SilentlyContinue ...
foo -ErrorAction SilentlyContinue

# Results in this:
<#
I shouldn't see this
#>

Looking into this further, I've found the following info:

Stepping back from all of this, we need to do something differently in the module, and we need to do it consistently (as Get-GitHubTeam is not the only function in this module that uses throw for error handling, with the expectation that processing will stop afterwards).

Two clear approaches we can take:

  1. We can wrap every function within a
    try
    {
        # ... Existing function code
    }
    finally {}
    to ensure that any terminating errors within the function are truly treated that way.
  2. We can add
    trap { throw $_ }
    at the top of every function to ensure that any terminating errors get captured and re-thrown, ensuring that they're truly treated as terminating.

That being said, there may be cases (especially in the case of pipeline input that can contain multiple objects) where we may want to allow later objects in the pipeline to continue processing even if earlier ones failed. We'd need to look at this on a case-by-case basis and then attempt to come up with a clear plan for how we handle those situations consistently.

So, with all that being said, I'm open to some proposals for how folks things we should approach this. The try/finally is a lot more clear on what's happening, but it adds an additional indentation level to all of the functions vs the trap approach (which is much less common/more obtuse. Neither approach right now handles the multiple objects in pipeline input scenario either. I think we need an inventory of all exported methods, and a suggested approach on how we handle all of those, so that we can ensure we have a clearly established pattern for how any future code should handle this as well.

@petervandivier
Copy link
Author

The approach in #410 is perhaps inelegant but AFAICT it induces "correct" behavior for all scenarios. Is it perhaps worth applying a gross-but-functional implementation while you ponder a better solution?

If not, then FWIW I vote option 2 trap { throw $_ } since I don't think try {} finally {} makes it more human readable enough to offset the annoyance of the extra whitespace it introduces IMHO.

Pipeline input consideration suggests to me the #410 approach might be warranted though if it makes the actual behavior more correct than the alternates available at this time.

@petervandivier
Copy link
Author

From PowerShell/PowerShell#19500 (comment)

...throw in a function should be followed by return to protect against this.

Pairs with a long read https://jhoneill.github.io/powershell/2022/06/13/Errors.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This relates to a bug in the existing module. good first issue If you're new to the project (or to OSS in general) and you'd like to contribute, try this one. help wanted Anyone in the community is welcome to do this work
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants