Repository navigation
A 5.4.1 satellite with core 5.5.0 is refused as the core differ; satellites accept any later core while binding to its internals #169
Description
Found by a pre-release sweep of main @ eff80b4 (lens: delivery); reproduced with packed packages in a consumer outside the repository. Should be decided before the tag: the satellites' dependency range on core goes into the published 5.5.0 nuspecs and cannot change afterwards.
Problem
CustomMigrationsModelDiffer.ValidateNothingOnlyTheSatelliteRenders (#150) skips its refusals when IsSatelliteDiffer is true (CustomMigrationsModelDiffer.cs:1030, :1052). That member is internal virtual, false in core, and overridden only by the 5.5.0 satellites. A 5.4.1 satellite assembly was compiled before the member existed, so on core 5.5.0 its differ counts as the core differ and is refused.
NuGet allows this pairing. The 5.4.1 satellite nuspecs declare EFCore.ComplexIndexes 5.4.1, which means >= 5.4.1, so a consumer who references both packages and merges only the Dependabot PR for core gets satellite 5.4.1 with core 5.5.0. The restore and the build report no warning.
The 5.5.0 satellites still declare >= 5.5.0 on core while binding to its internals through InternalsVisibleTo. A later core release can therefore break a 5.5.0 satellite the same way, on a line that takes fixes until 2028.
Scenario
A consumer references EFCore.ComplexIndexes.PostgreSQL 5.4.1 and EFCore.ComplexIndexes 5.5.0 directly. They call UseNpgsqlComplexIndexes() and declare HasExclusionConstraint(x => x.Ship.City, x => x.Period, name: "ex_city_period").
- deps.json resolves
EFCore.ComplexIndexes 5.5.0next toEFCore.ComplexIndexes.PostgreSQL 5.4.1. GenerateCreateScript()throws.EnsureCreated(),Migrate()andmigrations addthrow the same way (the last three traced through the same check):
InvalidOperationException: 'Order' declares a PostgreSQL exclusion constraint ('ex_city_period'), but the model is diffed by the provider-agnostic core differ … call UseNpgsqlComplexIndexes() instead of UseComplexIndexes()
The consumer already calls UseNpgsqlComplexIndexes(). With both packages at 5.5.0, the same program renders EXCLUDE. The failure is loud, not silent, but its advice is wrong. By the same trace, not run: SQL Server 5.4.1 with core 5.5.0 is refused for a unique index over nullable columns.
Change
- In core, decide "satellite differ" without an override that older assemblies lack. Use the rule
ComplexIndexDesignTimeRegistration.IsSatelliteDifferalready applies: a type derived fromCustomMigrationsModelDifferin another assembly. This is the only fix that reaches the published 5.4.x satellites. - Pin each satellite's dependency on core to
[$(Version)], since the satellites bind to core internals. Then NuGet refuses a mixed pair at restore instead of running it.
Test
A PackagingConventionTests assertion that each satellite's nuspec declares core as [x.y.z]. A core unit test that a CustomMigrationsModelDiffer subclass from another assembly, without the override, is not refused.
Activity
CaffeinatedCoder commentedon Oct 20, 2026
Fixed in #174, with a different runtime change from the one proposed above.
[$(Version)]. The three packages always ship together, so an exact pin never refuses a released pair. A range up to the next minor would accept core 5.5.1 under satellite 5.5.0, which is the pair to keep out.>=, so the pin doesn't reach them.The test for that last point checks that a subclass in an assembly that isn't a satellite is left alone.
Merge pull request #174 from CaffeinatedCoder/fix/169-satellite-core-pin