beeradmoore/dlss-swapper · error · Exception

LocalRecord was null when attempting to extract dll from…

Error message

LocalRecord was null when attempting to extract dll from zip.

What it means

HandleExtractFromZip requires a populated DLLRecord.LocalRecord because the extraction target path (LocalRecord.ExpectedPath) comes from it; when LocalRecord is null the record has never had local installation state computed, so extraction cannot proceed and the library throws. This is an internal precondition/invariant failure in the download-and-extract pipeline.

Solutions

  1. Initialize the DLLRecord's LocalRecord (expected path/registration) before extracting from the zip
  2. Ensure the asset type is present in the manager's local records before invoking extraction
  3. Guard the call site: skip or initialize records with null LocalRecord

Example fix

// before
HandleExtractFromZip(zipArchive, dllRecord);
// after
if (dllRecord.LocalRecord is null)
{
    await dllRecord.InitializeLocalRecordAsync(); // or obtain record via manager lookup
}
HandleExtractFromZip(zipArchive, dllRecord);
Defensive patterns

Strategy: type-guard

Validate before calling

// before extraction
if (dllRecord.LocalRecord is null)
    await dllRecord.InitializeAsync(); // or fetch from manager registry

Type guard

bool CanExtract(DLLRecord r) => r.LocalRecord?.ExpectedPath is not null;

Try / catch

try
{
    HandleExtractFromZip(zipArchive, dllRecord);
}
catch (Exception ex) when (ex.Message.Contains("LocalRecord was null"))
{
    logger.LogError(ex, "Record {AssetType} not initialized; re-registering.", dllRecord.AssetType);
}

Prevention

When it happens

Trigger: Calling HandleExtractFromZip (or the download/extract flow that leads to it) with a DLLRecord whose LocalRecord was never initialized — e.g. a record constructed without EnsureLocalRecord/initialization, or one built for an asset type the manager never registered locally.

Common situations: Manifest record deserialized without local state; calling extraction APIs directly on a fresh DLLRecord; asset type missing from the local records dictionary so lookup returned null.

Related errors


AI-assisted analysis of beeradmoore/dlss-swapper@ab9b1e2d4b (2026-09-15). Data as JSON: /api/errors/22b10f6c12ed98e1. Report an issue: GitHub.

Appendix: source

Thrown at src/Data/DLLManager.cs:1385

            GameAssetType.XeSS => "libxess.dll",
            GameAssetType.XeSS_FG => "libxess_fg.dll",
            GameAssetType.XeLL => "libxell.dll",
            GameAssetType.XeSS_DX11 => "libxess_dx11.dll",
            _ => string.Empty,
        };
    }

    /// <summary>
    /// This handles extracting of the DLL from both downloaded and imported zips (when imported matches the hash of one that could be downloaded)
    /// </summary>
    /// <param name="zipArchive"></param>
    /// <param name="dllRecord"></param>
    /// <exception cref="Exception"></exception>
    internal static void HandleExtractFromZip(ZipArchive zipArchive, DLLRecord dllRecord)
    {
        if (dllRecord.LocalRecord is null)
        {
            throw new Exception("LocalRecord was null when attempting to extract dll from zip.");
        }

        var dllName = DLLManager.DllNameForGameAssetType(dllRecord.AssetType);
        var entry = zipArchive.Entries.Single(x => x.Name.Equals(dllName, StringComparison.OrdinalIgnoreCase));
        if (entry is null)
        {
            throw new Exception("Could not find dll in zip.");
        }
        else
        {
            Storage.CreateDirectoryForFileIfNotExists(dllRecord.LocalRecord.ExpectedPath);
            entry.ExtractToFile(dllRecord.LocalRecord.ExpectedPath, true);
        }
    }

}

View on GitHub (pinned to ab9b1e2d4b)