Skip to content

Using ModuleSpec syntax in RequiredModules causes incorrect "cyclic dependency" failuresΒ #2607

@Jaykul

Description

@Jaykul

If a module (A) specifies the version of it's dependencies (the way it should), like:

RequiredModules = @(@{ModuleName='B'; ModuleVersion='1.0'; })

Another module which takes the same dependency, and also depends on A will cause incorrect cyclic dependency errors.

Background

We recently split up a module into a few smaller modules, and created a meta-module to load them, such that a module "QMHelper" became: QM.Assembly, QM.Database, QM.Configuration, QM.Security, and ... QMHelper

Each of these modules depends on a few others, in a strictly linear fashion. E.g.:

QM.Assembly has no dependencies, but everything depends on it.
QM.Database depends only on QM.Assembly
QM.Configuration depends on QM.Database (and QM.Assembly)
...
QMHelper, of course, depends on every module, since it exists purely as an easy way to install them and import everything to maintain backwards compatibility.

Each of these dependencies is documented in the module's manifest with the minimum version and GUID. E.g. @{ModuleName='QM.Database'; ModuleVersion='1.0'; GUID='0b8a2968-ea14-4e63-9961-d1dbee54faa5'}

We believed that this was the right way to design large modules so that they can be installed easily, but only the parts that you need must be imported.

Bug Report:

A user script which had a #requires -modules QMHelper in it failed to run. The error says that QMHelper was not loaded, but they can't figure out why. If they Import-Module QMHelper first, it imports fine, and the script will run with no problems.

It turns out that a #requires statement counts as a level of dependency (just like RequiresModule), and when there are module versions involved, PowerShell gives up after just a few levels. Specifically, 5?

In our case, we were just under the limit, and everything worked fine as long as you explicitly called Import-Module -- but if you used a #requires -modules statement, or added our top-level module to your RequiredModules, it would refuse to import, and give a confusing and incorrect error message.

Steps to reproduce

I wrote a script to generate samples in a lot of different ways, but the simplest repro case is this:

$Env:PSModulePath += ";$pwd"
$last = @();
foreach($module in mkdir Test1, Test2, Test3, Test4, Test5 -Force) {
   New-ModuleManifest ($module.Name + "\" + $module.Name + ".psd1") -RequiredModules $last
   $global:last += @{ ModuleName = $Module.Name; ModuleVersion = '1.0' }
}
Import-Module Test5

Expected behavior

Import-Module should work, since the dependencies are simply linear.

Actual behavior

You'll get an error like this:

The required module 'Test3' is not loaded. 
The module 'Test3' has a requiredModule 'Test2' in its module manifest 
'C:\ModuleTestFolder\Test3\Test3.psd1' that points to a cyclic dependency.

There is, of course, no cyclic dependency, and just changing the RequiresModules hashtable to a simple module name will clear up the error.

$last = @();
foreach($module in mkdir Test1, Test2, Test3, Test4, Test5 -Force) {
   New-ModuleManifest ($module.Name + "\" + $module.Name + ".psd1") -RequiredModules $last.ModuleName
   $global:last += @{ ModuleName = $Module.Name; ModuleVersion = '1.0' }
}
Import-Module Test5

Without specifying the ModuleVersion in the manifest, you can go hundreds of layers deep.

Environment data

> $PSVersionTable
Name                           Value                   
----                           -----                   
PSVersion                      5.1.14393.206           
PSEdition                      Desktop                 
BuildVersion                   10.0.14393.206          
CLRVersion                     4.0.30319.42000         
WSManStackVersion              3.0                     
PSRemotingProtocolVersion      2.3                     
SerializationVersion           1.1.0.1                 

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions