dotnet/wpf · error · InvalidOperationException
SR.CannotChangePublishLicense
Error message
SR.CannotChangePublishLicense
What it means
SavePublishLicense throws InvalidOperationException with SR.CannotChangePublishLicense when the publish license is written after the transform's settings have been fixed (_fixedSettings == true). Once RM encryption settings are committed (e.g. after first use/flush), they are immutable for the lifetime of the transform. This protects the integrity of the encrypted compound file.
Solutions
- Create a new RightsManagementEncryptionTransform instance instead of reusing the fixed one
- Call SavePublishLicense exactly once, before the settings are fixed
- Check whether _fixedSettings-equivalent state (e.g. transform already initialized and flushed) before calling SavePublishLicense
- Restructure code so the publish license is determined up front, prior to any encryption work
Example fix
// before transform.SavePublishLicense(license1); transform.SavePublishLicense(license2); // throws // after transform.SavePublishLicense(license1); var transform2 = new RightsManagementEncryptionTransform(); transform2.SavePublishLicense(license2);
Defensive patterns
Strategy: validation
Validate before calling
if (transformIsFixed) throw new InvalidOperationException("Transform settings already fixed; create a new transform before calling SavePublishLicense"); Try / catch
try { transform.SavePublishLicense(license); } catch (InvalidOperationException ex) { /* recreate transform and retry once */ } Prevention
- Call SavePublishLicense exactly once per transform, immediately after initialization
- Never reuse a RightsManagementEncryptionTransform across documents
- Order initialization so the license is known before settings are fixed
When it happens
Trigger: Calling RightsManagementEncryptionTransform.SavePublishLicense after InitializeRMForCreate has completed and _fixedSettings was set to true; attempting to set a second publish license on the same transform instance.
Common situations: Reusing a cached RightsManagementEncryptionTransform instance across multiple protected documents; calling SavePublishLicense twice during package creation; retry logic that re-invokes initialization plus SavePublishLicense on a already-fixed transform.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.CannotChangeCryptoProvider
- SR.Enumerator_VerifyContext
- Animation_Invalid_DefaultValue
- ArgumentOutOfRangeException(authentication)
- ArgumentOutOfRangeException(authenticationType)
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/80b7be0e4a14e223.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs:198
/// If <paramref name="publishLicense"/> is null.
/// </exception>
/// <exception cref="FileFormatException">
/// If the existing RM instance data in this file cannot be updated by the current version
/// of this class.
/// </exception>
/// <exception cref="InvalidOperationException">
/// If the transform settings are fixed.
/// </exception>
internal void
SavePublishLicense(
PublishLicense publishLicense
)
{
ArgumentNullException.ThrowIfNull(publishLicense);
if (_fixedSettings)
{
throw new InvalidOperationException(SR.CannotChangePublishLicense);
}
// We seek to position 0 but under the covers, the VersionedStream maintains a FormatVersion
// structure before our logical position zero.
_publishLicenseStream.Seek(0, SeekOrigin.Begin);
//
// Construct a BinaryWriter to write the rest of the instance data.
//
// Although BinaryWriter is IDisposable, we must not Close or Dispose it,
// as that would close the underlying stream, which we do not own. Simply
// allowing the BinaryWriter to be finalized after it goes out of scope
// does -not- close the underlying stream.
//
// The stream is not owned by the BlockManager, therefore we cannot
// close the BinaryWriter, as that would Close the stream underneath.View on GitHub (pinned to 81131a70a4)