Changing A Strong Name Is A Major Breaking Change

Recently, the Log4Net team released log4net 1.2.11 (congrats by the way!). The previous version of log4Net was 1.2.10.

Despite which version of version you subscribe to, we can all agree that only incrementing the third part of a version indicates that the new release is a minor update and one that hopefully has no breaking changes. Perhaps a bug fix release.

This is especially true if you subscribe to Semantic Versioning (SemVer) as NuGet does. As I wrote previously,

SemVer is a convention for versioning your public APIs that gives meaning to the version number. Each version has three parts, Major.Minor.Patch.

In brief, these correspond to:

  • Major: Breaking changes.
  • Minor: New features, but backwards compatible.
  • Patch: Backwards compatible bug fixes only.

Given that the Patch number is supposed to represent bug fixes only, NuGet chooses the minimum Major and Minor version of a package to meet the dependency contstraint, but the maximum Patch version. David Ebbo describes the algorithm and rationale in part 2 of his three part series on NuGet Versioning.

Strong Names and Versioning

The consequence of this is as follows. With the new log4Net release, if you have a package that has log4net 1.2.10 or greater as a dependency:

<dependency id="log4net" version="1.2.10" />

Installing that package would give you log4net 1.2.11. In most cases, this is what you want because the newer release might have important bug fixes such as security fixes.

However, in this case, Log4Net changed the strong name for their assembly for 1.2.11. Whatever your feelings about using strong names or not (that’s a separate discussion), the fact is that if you choose to use them, changing the strong name is changing the identity of your assembly. That’s a major breaking change.

And man, were a lot of people affected! We heard from tons of folks who were broken by this and unsure how to fix it.

NuGet does support a workaround so that you can prevent inadvertent upgrades. You can constrain the allowed versions of an installed package by manually modifying packages.config. Sadly, we don’t yet have a UI for this, so it’s a bit of a pain.

The Solution

Apart from never changing your strong name, the solution in this case is to treat this change as a major breaking change and increment the major version number of the assembly.

I don’t anticipate the Log4Net team will change the version of their assembly, but I reached out to the maintainer of the Log4Net package (no connection to the Log4Net team so please don’t give him grief about this) and he graciously incremented the major version of the Log4Net package to solve the problem.

Just to be clear, the log4net 2.0 NuGet package contains the log4net 1.2.11 assembly.

While it’s generally good form to have the package and assembly version match to avoid confusion, it’s not necessary. This is a good example of a case where they need to differ. I do suggest having the “Title” and “Description” note this fact to help avoid further confusion.

I want to thank Jiri for maintaining the Log4Net package and being responsive to the need out there! It’s much appreciated.

What others have said

Requesting Gravatar... Tanveer Badar Feb 17, 2012 7:00 AM
# re: Changing A Strong Name Is A Major Breaking Change
Your post looks very very odd in RSS viewer built into IE. Entire later half is in bold, as if you were screaming at the top of your lungs.
Requesting Gravatar... Adam Ralph Feb 17, 2012 7:25 AM
# re: Changing A Strong Name Is A Major Breaking Change
"the log4net 2.0 NuGet package contains the log4net 1.2.11 assembly" - hmmm... while understand the technical reasoning behind it (I also use SemVer for my products), I think this may get very confusing. We have got very used to the NuGet package version matching the product version.

What about those not using NuGet? I might be using 1.2.10 and I might wander over to the log4net site (or some other mirror hosting the binary), see 1.2.11 which (according to SemVer is a patch release) and grab the binaries, not realising that what I'm actually moving to is something which should be called 2.0.0.

I'm not sure how to resolve this, but I am rather worried about the confusion that may ensue if this kind of divergence continues. Ultimately, the correct technical solution would be to align all the version numbers involved in the product to 2.0.0 (I guess this would now have to be 2.0.1 if this were to happen).
Requesting Gravatar... Adam Ralph Feb 17, 2012 9:12 AM
# re: Changing A Strong Name Is A Major Breaking Change
Just to expand on my earlier comment:-

IMHO, several mistakes have been made here

1) changing the strong name - I've read the justification and I find it difficult to agree with

2) only incrementing the patch version - according to SemVer the version should have been 2.0.0. I can understand reluctance to increment the major version (for marketing reasons, etc.) but if a decision is taken not to do this, then I think, as a compromise, at least the minor version should have been incremented, i.e. 1.3.0, just to indicate that this is not just a patch but contains actual changes. Note that by not incrementing the major version, log4net have effectively chosen NOT to follow SemVer (a choice they are free to make).

3) the nuget package version should not have diverged from the product version (if the 1.3.0 compromise had been used then the nuget package could also have just incremented to 1.3.0). This doesn't follow SemVer, but it reflects log4net's decision not to follow SemVer. I don't see the point in forcing SemVer in nuget for a product that doesn't use SemVer itself - this will only cause confusion.

I think the situation we are left in now is quite undesirable and I think the nuget version and product version should be aligned. However, the nuget package is now locked into being > 2.0.0 which means an alignment of the versions can only happen if log4net moves to 2.0.0 itself.

I guess another solution would be to delete the 2.0.0 nuget package (by nuget gallery admin) and release 1.3.0 , apologising for the inconvenience caused to anyone who has already updated to the 2.0.0 package. Given the age of the package (~24 hours) this may be a feasible solution. Of course, if a decision could be made to use the old key package for nuget, then this could be pushed as 1.2.12 since the strong name change would effectively be backed out.
Requesting Gravatar... Egor Pavlikhin Feb 21, 2012 4:16 AM
# re: Changing A Strong Name Is A Major Breaking Change
Thank you for that!

This has been a major nuisance for several of our projects, and we were initially blaming NuGet, having to resort to manual package installation.

I think NuGet is putting to much trust into developers to correctly use version numbers to identify breaking changes. It wouldn't be unwise to specifically ask if a version upgrade is desired, rather than automatically upgrading packages with same major version.
Requesting Gravatar... Scott Koon Feb 22, 2012 7:11 PM
# re: Changing A Strong Name Is A Major Breaking Change
Having been through some pain with NPM, your package should never AUTOMATICALLY depend on version X OR HIGHER. It seems irresponsible to me to claim that you are compatible with ANY POSSIBLE CHANGE that a new version could contain.
Requesting Gravatar... Dricks Mar 09, 2012 6:11 PM
# Changing SIGNATURE AND Changing A Strong Name ARE Major Breaking Changes
They have done two breaking changes :

- They changed their strong name (which is definitively the baddest idea one can have).

-They changed the signature of log4net.Config.XmlConfigurator.Configure from 'returns void' to 'returns ICollection', which is backward compatibility breaker.
I now get some type loader exception saying it can't find method 'log4net.Config.XmlConfigurator.Configure' because another library uses 1.2.10 signature of the Configure method.

So please, definitively remove 1.2.11 version from your projects and stay with 1.2.10 or you will break any other using 1.2.10

What do you have to say?

(will show your gravatar)
Please add 6 and 6 and type the answer here: