Summary
The ElBruno.LocalLLMs 0.20.11 NuGet package ships ElBruno.LocalLLMs.dll stamped with
AssemblyVersion 0.20.9.0, while the sibling packages released at the same time
(ElBruno.LocalLLMs.BlazorComponents and ElBruno.LocalLLMs.Rag 0.20.11) were compiled against
ElBruno.LocalLLMs, Version=0.20.11.0.
.NET rolls assembly references forward but never backward, so the reference cannot bind and
any app that uses the core package together with BlazorComponents or Rag crashes at startup.
Impact
Hard startup crash, no graceful degradation:
Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly
'ElBruno.LocalLLMs, Version=0.20.11.0, Culture=neutral, PublicKeyToken=null'.
The system cannot find the file specified.
File name: 'ElBruno.LocalLLMs, Version=0.20.11.0, Culture=neutral, PublicKeyToken=null'
at ElBruno.LocalLLMs.BlazorComponents.Extensions.BlazorComponentsServiceExtensions.AddLocalLLMsBlazorComponents(IServiceCollection services, Action`1 configure)
at Program.<Main>$(String[] args)
The message is misleading — the file is present in the output folder; it is the version
downgrade that fails to bind.
Evidence
Reading AssemblyVersion straight out of the packages in ~/.nuget/packages:
| Package |
Package version |
AssemblyVersion |
ElBruno.LocalLLMs |
0.20.9 |
0.20.9.0 ✅ |
ElBruno.LocalLLMs.BlazorComponents |
0.20.9 |
0.20.9.0 ✅ |
ElBruno.LocalLLMs |
0.20.10 |
0.20.10.0 ✅ |
ElBruno.LocalLLMs.BlazorComponents |
0.20.10 |
0.20.10.0 ✅ |
ElBruno.LocalLLMs |
0.20.11 |
0.20.9.0 ❌ |
ElBruno.LocalLLMs.BlazorComponents |
0.20.11 |
0.20.11.0 ✅ |
ElBruno.LocalLLMs.Rag |
0.20.11 |
0.20.11.0 ✅ |
Reproduce:
$root = "$env:USERPROFILE\.nuget\packages"
foreach ($v in '0.20.9','0.20.10','0.20.11') {
foreach ($p in 'elbruno.localllms','elbruno.localllms.blazorcomponents') {
$f = Get-ChildItem "$root\$p\$v\lib\*\*.dll" -ErrorAction SilentlyContinue | Select-Object -First 1
if ($f) {
$n = [System.Reflection.AssemblyName]::GetAssemblyName($f.FullName)
"{0,-40} pkg={1,-8} AssemblyVersion={2}" -f $p, $v, $n.Version
}
}
}
Note the FileVersion is also 0.20.9.0, so it looks like the version stamp was not
propagated to the core project for this release (the release was cut from a branch/state where
Version/VersionPrefix was still 0.20.9, or the property is only applied to the satellite
projects).
Steps to reproduce
- Create a .NET 8/10 Blazor Server app.
dotnet add package ElBruno.LocalLLMs --version 0.20.11
dotnet add package ElBruno.LocalLLMs.BlazorComponents --version 0.20.11
- Call
builder.Services.AddLocalLLMsBlazorComponents(); in Program.cs.
dotnet run → FileNotFoundException before the host starts.
Expected
All packages published under the same release stamp a matching AssemblyVersion, so
ElBruno.LocalLLMs 0.20.11 exposes AssemblyVersion 0.20.11.0.
Suggested fix
-
Set Version / VersionPrefix in Directory.Build.props (or a shared Versions.props) so
every packable project — including ElBruno.LocalLLMs itself — is stamped from one source.
-
Add a release check that fails if any packed assembly's AssemblyVersion does not match its
package version. A few lines are enough:
Get-ChildItem artifacts\*.nupkg | ForEach-Object { <# expand, compare AssemblyName.Version to package version #> }
-
Consider setting <AssemblyVersion>$(VersionPrefix)</AssemblyVersion> explicitly rather than
relying on the default derivation, since a stale AssemblyVersion is invisible in
dotnet list package and only shows up at runtime.
Workaround for consumers
Until a fixed package ships, an AssemblyLoadContext.Default.Resolving handler registered from
a [ModuleInitializer] (so it runs before Main is JIT-compiled) can bind the request to the
DLL that is actually in the output folder:
internal static class LocalLLMsAssemblyVersionShim
{
private const string AssemblyName = "ElBruno.LocalLLMs";
[ModuleInitializer]
internal static void Initialize() => AssemblyLoadContext.Default.Resolving += Resolve;
private static Assembly? Resolve(AssemblyLoadContext context, AssemblyName requested)
{
if (!string.Equals(requested.Name, AssemblyName, StringComparison.OrdinalIgnoreCase))
return null;
var path = Path.Combine(AppContext.BaseDirectory, $"{AssemblyName}.dll");
if (!File.Exists(path))
return null;
var loaded = context.Assemblies.FirstOrDefault(
a => string.Equals(a.GetName().Name, AssemblyName, StringComparison.OrdinalIgnoreCase));
return loaded ?? context.LoadFromAssemblyPath(path);
}
}
Environment
Summary
The
ElBruno.LocalLLMs0.20.11 NuGet package shipsElBruno.LocalLLMs.dllstamped withAssemblyVersion 0.20.9.0, while the sibling packages released at the same time(
ElBruno.LocalLLMs.BlazorComponentsandElBruno.LocalLLMs.Rag0.20.11) were compiled againstElBruno.LocalLLMs, Version=0.20.11.0..NET rolls assembly references forward but never backward, so the reference cannot bind and
any app that uses the core package together with BlazorComponents or Rag crashes at startup.
Impact
Hard startup crash, no graceful degradation:
The message is misleading — the file is present in the output folder; it is the version
downgrade that fails to bind.
Evidence
Reading
AssemblyVersionstraight out of the packages in~/.nuget/packages:ElBruno.LocalLLMsElBruno.LocalLLMs.BlazorComponentsElBruno.LocalLLMsElBruno.LocalLLMs.BlazorComponentsElBruno.LocalLLMsElBruno.LocalLLMs.BlazorComponentsElBruno.LocalLLMs.RagReproduce:
Note the
FileVersionis also0.20.9.0, so it looks like the version stamp was notpropagated to the core project for this release (the release was cut from a branch/state where
Version/VersionPrefixwas still0.20.9, or the property is only applied to the satelliteprojects).
Steps to reproduce
dotnet add package ElBruno.LocalLLMs --version 0.20.11dotnet add package ElBruno.LocalLLMs.BlazorComponents --version 0.20.11builder.Services.AddLocalLLMsBlazorComponents();inProgram.cs.dotnet run→FileNotFoundExceptionbefore the host starts.Expected
All packages published under the same release stamp a matching
AssemblyVersion, soElBruno.LocalLLMs0.20.11 exposesAssemblyVersion 0.20.11.0.Suggested fix
Set
Version/VersionPrefixinDirectory.Build.props(or a sharedVersions.props) soevery packable project — including
ElBruno.LocalLLMsitself — is stamped from one source.Add a release check that fails if any packed assembly's
AssemblyVersiondoes not match itspackage version. A few lines are enough:
Consider setting
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>explicitly rather thanrelying on the default derivation, since a stale
AssemblyVersionis invisible indotnet list packageand only shows up at runtime.Workaround for consumers
Until a fixed package ships, an
AssemblyLoadContext.Default.Resolvinghandler registered froma
[ModuleInitializer](so it runs beforeMainis JIT-compiled) can bind the request to theDLL that is actually in the output folder:
Environment