PrismLibrary/Prism · error · InvalidOperationException

Resources.ModulePathCannotBeNullOrEmpty

Error message

Resources.ModulePathCannotBeNullOrEmpty

What it means

DirectoryModuleCatalog (.NET Framework build) throws InvalidOperationException when ModulePath is null or empty. This catalog scans a directory on disk for assemblies containing modules, so a path is mandatory. The check happens first in InnerLoad before any directory scanning or child AppDomain creation.

Solutions

  1. Set ModulePath to an existing directory containing your module assemblies before calling Load(): catalog.ModulePath = @".\Modules";
  2. If the path comes from configuration, ensure the config value is present and non-empty.
  3. Add a startup assertion/log if ModulePath is resolved dynamically so misconfiguration is caught early.
  4. Consider DirectoryModuleCatalog from the config-based setup only when directory scanning is actually needed.

Example fix

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

// after
var catalog = new DirectoryModuleCatalog { ModulePath = @".\Modules" };
catalog.Load();
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrEmpty(catalog.ModulePath))
    throw new InvalidOperationException("DirectoryModuleCatalog.ModulePath must be set before Load().");

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Creating a DirectoryModuleCatalog and calling Load() without setting the ModulePath property, or setting it to an empty string.

Common situations: Configuring directory-based module discovery but forgetting ModulePath; reading the path from config and the config key is empty/missing; refactoring moved the path assignment away from catalog creation.

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/15af436b7b50d4ea. Report an issue: GitHub.

Appendix: source

Thrown at src/Wpf/Prism.Wpf/Modularity/DirectoryModuleCatalog.net45.cs:34

    /// Assemblies are loaded into a new application domain with ReflectionOnlyLoad.  The application domain is destroyed
    /// once the assemblies have been discovered.
    ///
    /// The diretory catalog does not continue to monitor the directory after it has created the initialze 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 = BuildChildDomain(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"
                                        // TODO: Do this in a less hacky way... probably never gonna happen
                                        && !assembly.GetName().Name.StartsWith("xunit")
                                        && !string.IsNullOrEmpty(assembly.Location)

View on GitHub (pinned to 358118cd64)