stride3d/stride · error · InvalidOperationException

Package RootDirectory is null

Error message

Package RootDirectory is null

What it means

This internal refresh helper (CollectFiles) requires package.RootDirectory to be set before it can enumerate files for the package. A null RootDirectory means the package has no root folder association, so enumeration is impossible and it throws InvalidOperationException.

Solutions

  1. Set package.RootDirectory to the package's folder before refreshing
  2. Ensure the package is loaded via the normal load pipeline so RootDirectory is populated
  3. Skip refresh for in-memory packages without a root directory

Example fix

// before
RefreshPackageFiles(newInMemoryPackage);
// after
if (newInMemoryPackage.RootDirectory is null)
    newInMemoryPackage.RootDirectory = packageFolder;
RefreshPackageFiles(newInMemoryPackage);
Defensive patterns

Strategy: type-guard

Validate before calling

if (package.RootDirectory is null) throw new InvalidOperationException("Set RootDirectory before refresh");

Type guard

bool CanRefresh(Package p) => p.RootDirectory is not null && Directory.Exists(p.RootDirectory);

Try / catch

try { RefreshPackageFiles(pkg); } catch (InvalidOperationException ex) when (ex.Message.Contains("RootDirectory")) { pkg.RootDirectory = rootFolder; RefreshPackageFiles(pkg); }

Prevention

When it happens

Trigger: Calling the package file-collection/refresh routine on a Package instance whose RootDirectory property is null — typically a package not loaded from/saved to disk.

Common situations: Programmatically constructed in-memory Package objects passed to refresh; deserialization that omitted RootDirectory; packages loaded from sources that don't set the root.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/7c5c79a08202f858. Report an issue: GitHub.

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/Package.cs:1238

        foreach (var folder in AssetFolders)
        {
            var folderPath = RootDirectory is not null ? UPath.Combine(RootDirectory, folder.Path) : folder.Path;
            if (!existingAssetFolders.Contains(folderPath))
            {
                existingAssetFolders.Add(folderPath);
            }
        }
        return existingAssetFolders;
    }

    public static List<PackageLoadingAssetFile> ListAssetFiles(Package package, bool listAssetsInMsbuild, bool listUnregisteredAssets)
    {
        var listFiles = new List<PackageLoadingAssetFile>();

        // TODO Check how to handle refresh correctly as a public API
        if (package.RootDirectory is null)
        {
            throw new InvalidOperationException("Package RootDirectory is null");
        }

        if (!Directory.Exists(package.RootDirectory))
        {
            return listFiles;
        }

        // Iterate on each source folders
        foreach (var sourceFolder in package.GetDistinctAssetFolderPaths())
        {
            // Lookup all files
            foreach (var directory in FileUtility.EnumerateDirectories(sourceFolder, SearchDirection.Down))
            {
                foreach (var filePath in directory.GetFiles())
                {
                    // Don't load package via this method
                    if (filePath.FullName.EndsWith(PackageFileExtension, StringComparison.OrdinalIgnoreCase))
                    {

View on GitHub (pinned to 96fad776d2)