BornToBeRoot/NETworkManager · critical · InvalidOperationException

Could not load PSDiscoveryProtocol.psm1

Error message

Could not load PSDiscoveryProtocol.psm1

What it means

The DiscoveryProtocolCapture constructor reads the embedded resource NETworkManager.Models.Resources.PSDiscoveryProtocol.psm1 from the executing assembly. If the manifest resource stream is null (resource missing from the build or assembly), it throws InvalidOperationException('Could not load PSDiscoveryProtocol.psm1'), preventing any LLDP/CDP capture from starting.

Solutions

  1. Rebuild NETworkManager.Models ensuring PSDiscoveryProtocol.psm1 is included as EmbeddedResource in the csproj.
  2. Verify the resource exists: Assembly.GetExecutingAssembly().GetManifestResourceNames() should contain the full name.
  3. Redeploy the complete application (no trimmed/partial assemblies).
  4. Catch the exception in the caller and disable the LLDP/CDP feature with a clear message.

Example fix

// before
var capture = new DiscoveryProtocolCapture(); // throws if resource missing
// after
try
{
    var capture = new DiscoveryProtocolCapture();
}
catch (InvalidOperationException ex)
{
    Log.Error("LLDP/CDP capture unavailable: embedded PowerShell module missing", ex);
}
Defensive patterns

Strategy: fallback

Validate before calling

// verify the embedded module is present before constructing
var names = typeof(DiscoveryProtocolCapture).Assembly.GetManifestResourceNames();
bool ok = names.Contains("NETworkManager.Models.Resources.PSDiscoveryProtocol.psm1");

Type guard

null

Try / catch

try
{
    var capture = new DiscoveryProtocolCapture();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("PSDiscoveryProtocol.psm1"))
{
    Log.Error("Embedded discovery protocol module missing; LLDP/CDP disabled", ex);
    // disable the feature in the UI instead of crashing
}

Prevention

When it happens

Trigger: Constructing DiscoveryProtocolCapture when the assembly was built without the embedded .psm1 resource (wrong project/RESOURCE include), or loading the assembly from a modified/incomplete deployment (e.g. trimmed publish or a mismatched NETworkManager.Models.dll).

Common situations: Custom builds where Resources\PSDiscoveryProtocol.psm1 was not embedded (EmbeddedResource missing in csproj); publishing with trimming that stripped resources; running a partially copied portable deployment.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of BornToBeRoot/NETworkManager@2780d65469 (2026-09-12). Data as JSON: /api/errors/391570394aa9768e. Report an issue: GitHub.

Appendix: source

Thrown at Source/NETworkManager.Models/Network/DiscoveryProtocol.cs:29

///     Class to capture network discovery protocol packages.
/// </summary>
public class DiscoveryProtocolCapture
{
    /// <summary>
    ///     Holds the PowerShell script which is loaded when the class is initialized.
    /// </summary>
    private readonly string _psDiscoveryProtocolModule;

    /// <summary>
    ///     Initializes a new instance of the <see cref="DiscoveryProtocol" /> class.
    /// </summary>
    public DiscoveryProtocolCapture()
    {
        using var stream = Assembly.GetExecutingAssembly()
            .GetManifestResourceStream("NETworkManager.Models.Resources.PSDiscoveryProtocol.psm1");

        using StreamReader reader =
            new(stream ?? throw new InvalidOperationException("Could not load PSDiscoveryProtocol.psm1"));

        _psDiscoveryProtocolModule = reader.ReadToEnd();
    }

    /// <summary>
    ///     Is triggered when a network package with a discovery protocol is received.
    /// </summary>
    public event EventHandler<DiscoveryProtocolPackageArgs> PackageReceived;

    /// <summary>
    ///     Triggers the <see cref="PackageReceived" /> event.
    /// </summary>
    /// <param name="e">Passes <see cref="DiscoveryProtocolPackageArgs" /> to the event.</param>
    protected virtual void OnPackageReceived(DiscoveryProtocolPackageArgs e)
    {
        PackageReceived?.Invoke(this, e);
    }

View on GitHub (pinned to 2780d65469)