PrismLibrary/Prism · error · InvalidOperationException

Resources.ModulePathCannotBeNullOrEmpty

Error message

Resources.ModulePathCannotBeNullOrEmpty

What it means

DirectoryModuleCatalog (.NET Core/.NET 5+ build) throws InvalidOperationException when ModulePath is null or empty. As in the .NET Framework variant, this catalog discovers modules by scanning a directory, so a valid path is required. The check is the first statement of InnerLoad, before any file-system access.

Solutions

  1. Assign ModulePath before Load: catalog.ModulePath = Path.Combine(AppContext.BaseDirectory, "Modules");
  2. If the path comes from IConfiguration, validate it is non-empty at startup (fail fast).
  3. Default to the application base directory plus 'Modules' when no explicit path is configured.
  4. Add a unit test that builds the catalog the same way as production to surface the misconfiguration early.

Example fix

// before
var catalog = new DirectoryModuleCatalog(); // ModulePath never set
catalog.Load();

// after
var catalog = new DirectoryModuleCatalog { ModulePath = Path.Combine(AppContext.BaseDirectory, "Modules") };
catalog.Load();
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrWhiteSpace(catalog.ModulePath))
    catalog.ModulePath = Path.Combine(AppContext.BaseDirectory, "Modules");

Type guard

static bool HasModulePath(DirectoryModuleCatalog c) => !string.IsNullOrWhiteSpace(c.ModulePath);

Try / catch

try { catalog.Load(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("ModulePath")) { logger.LogError(ex, "ModulePath not configured"); }

Prevention

When it happens

Trigger: Constructing a DirectoryModuleCatalog on .NET Core and calling Load() without assigning ModulePath, or assigning an empty string (e.g. from a missing config value).

Common situations: Empty appsettings/section value for the modules directory; forgetting the property when migrating from a config-based catalog; DI-constructed catalog where path injection was skipped.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of PrismLibrary/Prism@358118cd64 (2026-09-15). Data as JSON: /api/errors/c4a51ef367959e57. Report an issue: GitHub.

Appendix: source

Thrown at src/Wpf/Prism.Wpf/Modularity/DirectoryModuleCatalog.netcore.cs:36

    /// Assemblies are loaded into a new application domain with ReflectionOnlyLoad.  The application domain is destroyed
    /// once the assemblies have been discovered.
    ///
    /// The directory catalog does not continue to monitor the directory after it has created the initialize catalog.
    /// </remarks>
    public class DirectoryModuleCatalog : ModuleCatalog
    {
        /// <summary>
        /// Directory containing modules to search for.
        /// </summary>
        public string ModulePath { get; set; }

        /// <summary>
        /// Drives the main logic of building the child domain and searching for the assemblies.
        /// </summary>
        protected override void InnerLoad()
        {
            if (string.IsNullOrEmpty(ModulePath))
                throw new InvalidOperationException(Resources.ModulePathCannotBeNullOrEmpty);

            if (!Directory.Exists(ModulePath))
                throw new InvalidOperationException(
                    string.Format(CultureInfo.CurrentCulture, Resources.DirectoryNotFound, ModulePath));

            AppDomain childDomain = AppDomain.CurrentDomain;

            try
            {
                List<string> loadedAssemblies = new List<string>();

                var assemblies = (
                    from Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()
                    where !(assembly is System.Reflection.Emit.AssemblyBuilder)
                        && assembly.GetType().FullName != "System.Reflection.Emit.InternalAssemblyBuilder"
                        && !String.IsNullOrEmpty(assembly.Location)
                    select assembly.Location
                );

View on GitHub (pinned to 358118cd64)