Description
The _CheckGrpcNetClientFactoryVersion MSBuild target shipped by Microsoft.Extensions.Http.Resilience (buildTransitive/net8.0/Microsoft.Extensions.Http.Resilience.targets) feeds the Grpc.Net.ClientFactory version string directly into [MSBuild]::VersionLessThan(...) without validating that it is a parseable Version.
When a consumer pins the package using NuGet bracket notation - either via <PackageReference ... Version="[x.y.z]" /> directly, or via Central Package Management (<PackageVersion ... Version="[x.y.z]" />) - the function throws and the whole build fails before any compilation happens.
Reproduction Steps
Single-file repro (repro.csproj, no source code needed):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.7.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="[2.80.0]" />
</ItemGroup>
</Project>
dotnet build repro.csproj
Expected behavior
Build succeeds. NuGet has accepted [x.y.z] (exact-version pin) as a valid Version string on PackageReference / PackageVersion for years; tooling that consumes it should either parse it as a VersionRange and extract the underlying Version, or skip the check rather than crash the build. The pinned version (2.80.0) is also well above the 2.64.0 threshold the target was designed to warn about, so the check has nothing to flag.
Actual behavior
error MSB4184: The expression "[MSBuild]::VersionLessThan([2.80.0], 2.64.0)" cannot be evaluated.
Version string was not in a correct format.
[/path/to/repro.csproj]
Build FAILED.
0 Warning(s)
1 Error(s)
Regression?
I have not bisected this. The _CheckGrpcNetClientFactoryVersion target was added in Microsoft.Extensions.Http.Resilience somewhere in the 8.x line; the same crash reproduces on 10.6.0 and 10.7.0 (latest at time of writing). I have not tested whether earlier major versions (e.g. 8.x, 9.x) without the target are affected - the bug only exists where the target exists.
Known Workarounds
Set <SuppressCheckGrpcNetClientFactoryVersion>true</SuppressCheckGrpcNetClientFactoryVersion> in the consuming project. This is documented in the warning text emitted by the same target, but it should not be required for consumers who are already on a compatible Grpc version and merely happen to pin it with brackets.
Configuration
| Component |
Value |
Microsoft.Extensions.Http.Resilience |
10.6.0 and 10.7.0 (both reproduce identically) |
Grpc.Net.ClientFactory |
2.80.0 (any bracket-pinned version reproduces) |
| .NET SDK |
10.0.100 |
| OS |
Linux (Ubuntu under WSL) - same MSBuild logic on Windows, so likely also affected |
The crash happens regardless of whether bracket notation is used directly on PackageReference or centrally on PackageVersion (CPM). Both code paths in the target are vulnerable.
Other information
Affected file:
src/Libraries/Microsoft.Extensions.Http.Resilience/buildTransitive/net*/Microsoft.Extensions.Http.Resilience.targets
All four [MSBuild]::VersionLessThan(...) call sites in that file have the same problem:
%(_GrpcNetClientFactoryPackageReference.Version) (line ~30)
%(_GrpcNetClientFactoryPackageReference.VersionOverride) (line ~37)
%(_GrpcNetClientFactoryPackageVersion.Version) (line ~44)
%(_GrpcNetClientFactoryTransitiveDependency.NuGetPackageVersion) (line ~51)
Suggested fix: strip leading [ / trailing ] (and any version-range second element like [1.0.0,2.0.0)) before invoking VersionLessThan. Bracket notation is part of the public NuGet contract; the target should tolerate it.
Note that the official Known Issues docs describe this check as producing a "compilation warning" - but with bracket-pinned Version, it produces a build-failing MSB4184 error before any warning is emitted. The contract documented in the Known Issues section is therefore violated for any consumer that pins versions with [x.y.z] notation, even when they're already on a fully compatible Grpc version.
Description
The
_CheckGrpcNetClientFactoryVersionMSBuild target shipped byMicrosoft.Extensions.Http.Resilience(buildTransitive/net8.0/Microsoft.Extensions.Http.Resilience.targets) feeds theGrpc.Net.ClientFactoryversion string directly into[MSBuild]::VersionLessThan(...)without validating that it is a parseableVersion.When a consumer pins the package using NuGet bracket notation - either via
<PackageReference ... Version="[x.y.z]" />directly, or via Central Package Management (<PackageVersion ... Version="[x.y.z]" />) - the function throws and the whole build fails before any compilation happens.Reproduction Steps
Single-file repro (
repro.csproj, no source code needed):Expected behavior
Build succeeds. NuGet has accepted
[x.y.z](exact-version pin) as a validVersionstring onPackageReference/PackageVersionfor years; tooling that consumes it should either parse it as aVersionRangeand extract the underlyingVersion, or skip the check rather than crash the build. The pinned version (2.80.0) is also well above the2.64.0threshold the target was designed to warn about, so the check has nothing to flag.Actual behavior
Regression?
I have not bisected this. The
_CheckGrpcNetClientFactoryVersiontarget was added inMicrosoft.Extensions.Http.Resiliencesomewhere in the 8.x line; the same crash reproduces on10.6.0and10.7.0(latest at time of writing). I have not tested whether earlier major versions (e.g. 8.x, 9.x) without the target are affected - the bug only exists where the target exists.Known Workarounds
Set
<SuppressCheckGrpcNetClientFactoryVersion>true</SuppressCheckGrpcNetClientFactoryVersion>in the consuming project. This is documented in the warning text emitted by the same target, but it should not be required for consumers who are already on a compatible Grpc version and merely happen to pin it with brackets.Configuration
Microsoft.Extensions.Http.ResilienceGrpc.Net.ClientFactoryThe crash happens regardless of whether bracket notation is used directly on
PackageReferenceor centrally onPackageVersion(CPM). Both code paths in the target are vulnerable.Other information
Affected file:
src/Libraries/Microsoft.Extensions.Http.Resilience/buildTransitive/net*/Microsoft.Extensions.Http.Resilience.targetsAll four
[MSBuild]::VersionLessThan(...)call sites in that file have the same problem:%(_GrpcNetClientFactoryPackageReference.Version)(line ~30)%(_GrpcNetClientFactoryPackageReference.VersionOverride)(line ~37)%(_GrpcNetClientFactoryPackageVersion.Version)(line ~44)%(_GrpcNetClientFactoryTransitiveDependency.NuGetPackageVersion)(line ~51)Suggested fix: strip leading
[/ trailing](and any version-range second element like[1.0.0,2.0.0)) before invokingVersionLessThan. Bracket notation is part of the public NuGet contract; the target should tolerate it.Note that the official Known Issues docs describe this check as producing a "compilation warning" - but with bracket-pinned
Version, it produces a build-failingMSB4184error before any warning is emitted. The contract documented in the Known Issues section is therefore violated for any consumer that pins versions with[x.y.z]notation, even when they're already on a fully compatible Grpc version.