Changing A Strong Name Is A Major Breaking Change

open source, nuget, code 0 comments suggest edit

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.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

7 responses

  1. Avatar for Tanveer Badar
    Tanveer Badar February 17th, 2012

    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.

  2. Avatar for adamralph
    adamralph February 17th, 2012

    "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).

  3. Avatar for adamralph
    adamralph February 17th, 2012

    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.

  4. Avatar for Egor Pavlikhin
    Egor Pavlikhin February 21st, 2012

    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.

  5. Avatar for Scott Koon
    Scott Koon February 22nd, 2012

    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.

  6. Avatar for Dricks
    Dricks March 9th, 2012

    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

  7. Avatar for Kirk Broadhurst
    Kirk Broadhurst April 14th, 2016

    This was a huge issue for me at the time.

    It remains a huge issue. It seems that with every release the log4net team change the strong name of their assembly, whilst only updating the third component of the version number.

    Right now I'm trying to use *another* package from nuget which references log4net 1.2.14 (aka 2.0.4?). Thus I need to downgrade my version from 1.2.15 to 1.2.14. But what if I were to reference two packages that use different versions of log4net? I suppose I'd need to build at least one of those from source.

    The entire situation is ridiculous.