Repository navigation
Import-Module does not properly report errors to users #9855
Description
If you have a script module that generates a terminating error, the error message shown to users does not indicate that the error came from Import-Module. Instead it simply shows the script module internals. This is inappropriate for users who may not have authored that script module.
If you have a function in a script module that generates a terminating error, and you invoke that function when the module is not loaded, the module will load, the terminating error will not be shown to end users at all, and the function will run. The suppression of the terminating error in this scenario needs to be corrected so that users see the error came from Import-Module which was implicitly invoked by invoking the command while auto-loading is enabled.
Note: This issue is closely related to the problem with terminating error handling in PowerShell (for which a collection of RFCs have been submitted as a PR). Terminating error handling aside, this issue focuses on how Import-Module does a poor job of reporting errors, sometimes not even reporting them at all.
Steps to reproduce
$moduleName = 'ModuleErrorHandlingTest'
$modulePath = Join-Path -Path $([Environment]::GetFolderPath('MyDocuments')) -ChildPath PowerShell/Modules/${moduleName}
New-Item -Path $modulePath -ItemType Directory -Force > $null
$nmmParameters = @{
Path = "${modulePath}/${moduleName}.psd1"
RootModule = "./${moduleName}.psm1"
FunctionsToExport = @('Test-ErrorHandling')
}
New-ModuleManifest @nmmParameters
$scriptModulePath = Join-Path -Path $modulePath -ChildPath "${moduleName}.psm1"
New-Item -Path $scriptModulePath -ItemType File | Set-Content -Encoding UTF8 -Value @'
1/0 # Oops!
function Test-ErrorHandling {
[cmdletBinding()]
param()
'Error handling output'
}
'@
# This next command generates an error while loading the module, but the module still
# loads, and the error message does not tell the user that it came from Import-Module
# nor does it tell the user which module was being loaded when the error occurred.
Import-Module $moduleName
Remove-Module $moduleName
# This next command generates an error while implicitly loading a module, but the error
# is silenced and the module loads anyway so the end user has no idea that something
# happened.
Test-ErrorHandling
Remove-Module $moduleName
Remove-Item -LiteralPath $modulePath -Recurse -ForceExpected behavior
Note the differences in the actual error text that are shown in what should be expected when a module is loaded over what is actually shown below this code block.
Import-Module: Unexpected error while importing ModuleErrorHandlingTest module. Attempted to divide by zero.
At line:23 char:1
+ Import-Module $moduleName
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Import-Module: Unexpected error while implicitly importing ModuleErrorHandlingTest module. Attempted to divide by zero.
At line:29 char:1
+ Test-ErrorHandling
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Error handling output
Actual behavior
Attempted to divide by zero.
At C:\Users\kirka\OneDrive\Documents\PowerShell\Modules\ModuleErrorHandlingTest\ModuleErrorHandlingTest.psm1:1 char:5
+ 1/0 # Oops!
+ ~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Error handling output
Environment data
Name Value
---- -----
PSVersion 6.2.0
PSEdition Core
GitCommitId 6.2.0
OS Microsoft Windows 10.0.17763
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Activity
bpayette commentedon Jun 10, 2019
Kirk Munro (@KirkMunro)
So you are suggesting that
Import-Moduleshould catch all exceptions and wrap them in aPSModuleImportErrorException?Note: IMHO the module author should be dealing explicitly with errors and providing an appropriate experience for the end user rather than simply relying on the PowerShell runtime to take care of error handling and presentation.
KirkMunro commentedon Jun 10, 2019
Bruce Payette (@bpayette) Something like that.
Import-Modulefails (but they do because of how it handles errors).In my mind this means two things:
Import-Moduleso that...My goal here isn't to help module authors be lazy. It's to help end users identify where problems actually come from so that they can decide an appropriate course of action if an error occurs during module load.
iSazonov commentedon Jun 11, 2019
Is the issue only for Import-Module, or other module cmdlets too, or module behavior in common?
KirkMunro commentedon Jun 11, 2019
I haven't stepped through the code while reproducing the error, but as far as I know this is only in
Import-Module. The errors I have issue with occur while processing a psm1 file, which I don't believe is done anywhere outside of that cmdlet.fMichaleczek commentedon Jun 11, 2019
I'm agree. A little enhancement around module's error is a good thing !
bpayette commentedon Jun 12, 2019
Hey Kirk Munro (@KirkMunro)
First - kudos for trying to take on this problem. It's bugged me for years.
Hmm ... in your "expected output" example, you're still showing the line/line number in the module where the error occurred. I assume you intend that it should show the line where
Import-Modulewas called (orusing moduleor#requiresfor that matter)?WRT terminating errors, you can mostly get the behaviour you want simply by putting
trap { break }at the top level of your module but what you can't do is create aRuntimeExceptionand then set theInvocationInfoproperty so it points to where you want. If you trap/catch and then throw a new error it will report thethrowline, not the original line. Having a way to "point" an error message to the appropriate location would make it possible for the script/module author to provide a much better error experience.Also note that overarching problem doesn't just apply to modules. Scripts and functions have exactly the same problem. A user calling a script shouldn't be exposed to the internals of the script (at least not by default)
I totally get that. A big part of the problem is that script/function/module authors can be "lazy" about error handling and get an end-user error experience. Not ideal certainly but "free". For compiled-cmdlet authors, error handling isn't free so they need to put some thought into it.
KirkMunro commentedon Jun 12, 2019
Correct. I created that output via a quick copy-paste-modify. It should show the line where the error occurred from the eyes of the end user (explicit import via
Import-Module,using module, or#requires, or implicit import via invocation of a command that is in a module that has not been imported yet). I'll update the expected output in my post accordingly.Interesting point on how
RuntimeExceptioninstances could be configured with a specificInvocationInfo. I'm stepping through some of the code related to this to see how it works, and will keep this idea in mind.Bruce Payette (@bpayette): You mean scripts and functions that have the
CmdletBindingattribute, not all scripts and functions, right? If so, I agree. 😉My line in the sand on this is
CmdletBinding. If a script or function usesCmdletBinding, then the intent of that script or function is to be treated like a command, which is different than simple scripts or basic functions that are more often consumed by the author or a team, maybe shared as example code to be modified, but not shared as a finished product for end users to use as a black box. In scripts or functions that useCmdletBinding, I believe they should behave as much like a cmdlet as possible, not showing internals to people who invoke them.metablaster commentedon Dec 13, 2020
If your example module dot sources an external script that otherwise fails to be dot sourced then you will see no error.
Import-Modulewon't report an error in this case, but if you manually dot source said script the error is shown.That's pretty much unexpected behavior which I encountered today so upvoting this.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 23, 2023
This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.