Summary
The source control check enabled by VcsCheckEnabled does not run on a project that applies no aspect to its own code. The build fails with PS0242 even when every source file of the project is unmodified in version control. The licensing trace contains no record that the check was attempted.
Conditions
Both of these conditions must be met at the same time:
- No valid license key is available on the machine. The registry,
postsharp.config, the LicenseKeys property and any configured license server contain no key that is valid for the PostSharp version being built. An expired key has the same effect as no key at all.
- The project applies no aspect to its own code. Defining an aspect type is not sufficient to avoid this condition: the aspect must be applied to a declaration of the project, whether directly, by multicast, or by inheritance.
The state of the working tree does not matter. The check never runs, so a clean working tree gives the same result as a modified one. This is why setting VcsCheckEnabled to True appears to have no effect.
Scope
There are two reasons to reference PostSharp from a project: to define aspects, or to use them. Only the second one weaves anything into the project itself.
Condition 2 is therefore met by every project that defines aspects for other projects to use. An aspect library fails to build, even though its own source files are unmodified.
Condition 2 is also met by a project that references PostSharp but neither defines nor uses an aspect. This happens in a large solution when the reference arrives from a shared import such as Directory.Build.props or a solution-wide package reference.
The feature is documented to let a developer build unmodified code without consuming a license seat. For the projects described above, it does not.
Expected behavior
When VcsCheckEnabled is set to True and the source files of the project are unmodified in version control, the project builds successfully, whether or not it applies an aspect.
Actual behavior
The build fails with:
error PS0242: License error. No valid license key has been installed. To register a license key, see https://doc.postsharp.net/deploying-keys.
When the build runs with -p:PostSharpTrace=Licensing at detailed verbosity, the trace contains none of the three lines that the source control check writes:
The project is not modified.
The project is modified: ...
VCS check was not performed because ...
The absence of all three lines means that the check was not attempted. It does not mean that the check ran and refused.
Steps to reproduce
- Create a class library that defines an aspect and does not apply it to any declaration of the project.
- Add a
postsharp.config file with <Property Name="VcsCheckEnabled" Value="True" />.
- Commit the project to a git repository and leave the working tree clean.
- Make sure that no license key is registered on the machine.
- Build the project interactively.
The build fails with PS0242.
Workaround
Any license key that covers PostSharp Essentials satisfies the requirement that fails, because the failing check accepts any user license.
Root cause
The Unmodified license is created as a side effect of aspect weaving. For each woven aspect instance, AspectWeaverInstance calls LocalLicenseManager.RequireLicensedFeaturesForWeavedInstance. That call reaches IsRequirementSatisfiedByAssembly, which calls CheckVcs. CheckVcs runs git status --porcelain and, when the source files of the project are unmodified, registers the Unmodified license with SharedUserLicenseManager.
Project.CheckUserLicensePresent runs before the Generate phase and requires LicensedPackages.Essentials from a user license. It reads the license collection, but it never triggers the source control check itself. When no aspect instance is woven, nothing registers the Unmodified license, so the requirement fails and PS0242 is reported.
The Unattended license does not have this problem. SharedUserLicenseManager.TrySatisfyRequirement registers it on demand, on the same code path that CheckUserLicensePresent takes. This is why a continuous integration build of the same project succeeds while an interactive build of it fails.
Suggested fix
Register the Unmodified license on demand, in the same way as the Unattended license, so that CheckUserLicensePresent can satisfy its requirement from the source control check. This grants only what VcsCheckEnabled already promises, so it does not change licensing policy.
Note for investigation
There may be a second way to meet condition 2, which has not been verified. In IsRequirementSatisfiedByAssembly, an embedded license found in the aspect assembly returns before CheckVcs is called. Only the Framework package can be satisfied that way, so a project that uses the Pattern Libraries is not affected, because it also requires Logging, Threading or Caching. A project whose aspects come entirely from a library with an embedded redistribution license, and which requires nothing beyond Framework, may therefore behave in the same way. This should be confirmed before the fix is scoped.
Versions
The behavior described here was verified on the 2024.0 development line. The original report came from a customer on 2026.0.12, and the same behavior is expected there, but it has not yet been confirmed on that line.
— Claude for Gael
Summary
The source control check enabled by
VcsCheckEnableddoes not run on a project that applies no aspect to its own code. The build fails with PS0242 even when every source file of the project is unmodified in version control. The licensing trace contains no record that the check was attempted.Conditions
Both of these conditions must be met at the same time:
postsharp.config, theLicenseKeysproperty and any configured license server contain no key that is valid for the PostSharp version being built. An expired key has the same effect as no key at all.The state of the working tree does not matter. The check never runs, so a clean working tree gives the same result as a modified one. This is why setting
VcsCheckEnabledtoTrueappears to have no effect.Scope
There are two reasons to reference PostSharp from a project: to define aspects, or to use them. Only the second one weaves anything into the project itself.
Condition 2 is therefore met by every project that defines aspects for other projects to use. An aspect library fails to build, even though its own source files are unmodified.
Condition 2 is also met by a project that references PostSharp but neither defines nor uses an aspect. This happens in a large solution when the reference arrives from a shared import such as
Directory.Build.propsor a solution-wide package reference.The feature is documented to let a developer build unmodified code without consuming a license seat. For the projects described above, it does not.
Expected behavior
When
VcsCheckEnabledis set toTrueand the source files of the project are unmodified in version control, the project builds successfully, whether or not it applies an aspect.Actual behavior
The build fails with:
When the build runs with
-p:PostSharpTrace=Licensingat detailed verbosity, the trace contains none of the three lines that the source control check writes:The project is not modified.The project is modified: ...VCS check was not performed because ...The absence of all three lines means that the check was not attempted. It does not mean that the check ran and refused.
Steps to reproduce
postsharp.configfile with<Property Name="VcsCheckEnabled" Value="True" />.The build fails with PS0242.
Workaround
Any license key that covers PostSharp Essentials satisfies the requirement that fails, because the failing check accepts any user license.
Root cause
The
Unmodifiedlicense is created as a side effect of aspect weaving. For each woven aspect instance,AspectWeaverInstancecallsLocalLicenseManager.RequireLicensedFeaturesForWeavedInstance. That call reachesIsRequirementSatisfiedByAssembly, which callsCheckVcs.CheckVcsrunsgit status --porcelainand, when the source files of the project are unmodified, registers theUnmodifiedlicense withSharedUserLicenseManager.Project.CheckUserLicensePresentruns before the Generate phase and requiresLicensedPackages.Essentialsfrom a user license. It reads the license collection, but it never triggers the source control check itself. When no aspect instance is woven, nothing registers theUnmodifiedlicense, so the requirement fails and PS0242 is reported.The
Unattendedlicense does not have this problem.SharedUserLicenseManager.TrySatisfyRequirementregisters it on demand, on the same code path thatCheckUserLicensePresenttakes. This is why a continuous integration build of the same project succeeds while an interactive build of it fails.Suggested fix
Register the
Unmodifiedlicense on demand, in the same way as theUnattendedlicense, so thatCheckUserLicensePresentcan satisfy its requirement from the source control check. This grants only whatVcsCheckEnabledalready promises, so it does not change licensing policy.Note for investigation
There may be a second way to meet condition 2, which has not been verified. In
IsRequirementSatisfiedByAssembly, an embedded license found in the aspect assembly returns beforeCheckVcsis called. Only theFrameworkpackage can be satisfied that way, so a project that uses the Pattern Libraries is not affected, because it also requiresLogging,ThreadingorCaching. A project whose aspects come entirely from a library with an embedded redistribution license, and which requires nothing beyondFramework, may therefore behave in the same way. This should be confirmed before the fix is scoped.Versions
The behavior described here was verified on the 2024.0 development line. The original report came from a customer on 2026.0.12, and the same behavior is expected there, but it has not yet been confirmed on that line.
— Claude for Gael