dotnet/wpf · error · FileFormatException
SR.PublishLicenseStreamCorrupt
Error message
SR.PublishLicenseStreamCorrupt
What it means
RightsManagementEncryptionTransform.LoadPublishLicense reads the publish-license instance data stream from a rights-managed compound file. The first Int32 in that stream is the header length, which must at minimum cover itself (Int32Size = 4 bytes). If headerLen < 4, the stream content is not a valid publish-license header and FileFormatException(SR.PublishLicenseStreamCorrupt) is thrown.
Solutions
- Treat the file as corrupt: restore from backup or re-obtain the original rights-managed document.
- Re-save/re-publish the document from the originating application to rewrite the instance data stream.
- Inspect the RM transform's instance data stream in the compound file and confirm the first 4 bytes decode to a sane Int32 header length (>= 4).
- Catch FileFormatException during PublishLicense/OpenPackage and show a 'corrupt protected document' error instead of crashing.
- If writing such files yourself, ensure SavePublishLicense always emits the Int32 header length before any payload.
Example fix
// before: blindly opening a suspect file
var publishLicense = new PublishLicense(rmStreamData);
// after: validate the length prefix first
int headerLen = ReadInt32AtStart(rmStreamData);
if (headerLen < sizeof(int))
{
throw new InvalidDataException(
"Publish license header length is invalid; the protected document is corrupt.");
}
var publishLicense = new PublishLicense(rmStreamData); Defensive patterns
Strategy: validation
Validate before calling
// peek the header length before attempting to load
stream.Seek(0, SeekOrigin.Begin);
Span<byte> buf = stackalloc byte[4];
if (stream.Read(buf) < 4 || BitConverter.ToInt32(buf) < sizeof(int))
throw new InvalidDataException("Publish license header length invalid; file is corrupt."); Type guard
static bool HasValidLicenseHeader(Stream s)
{
long pos = s.Position;
Span<byte> b = stackalloc byte[4];
bool ok = s.Read(b) == 4 && BitConverter.ToInt32(b) >= 4;
s.Seek(pos, SeekOrigin.Begin);
return ok;
} Try / catch
try
{
publishLicense = transform.LoadPublishLicense();
}
catch (FileFormatException ex)
{
log.Error("Publish license header corrupt in protected document", ex);
throw new InvalidDataException("Protected document is corrupt; restore from a good copy.", ex);
} Prevention
- Validate hash/size of protected documents before opening.
- Never hand-craft or byte-patch RM instance data streams.
- Catch FileFormatException at package-open boundaries to degrade gracefully.
- Re-publish documents whose save was interrupted rather than retrying the bad copy.
When it happens
Trigger: Opening a rights-managed document whose primary instance data stream contains a header length field less than 4 (0, negative, or garbage bytes) — typically because the stream holds random/corrupt data or was written by a different format.
Common situations: Compound file corrupted by a failed save; a stream that was overwritten or truncated leaving zero bytes that get read as 0 length prefix; opening a file not actually produced by the RM encryption pipeline; byte-order or format mismatch from a hand-crafted file.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Document does not contain a package.
- Document does not contain any rights management-protected…
- SR.Format(SR.PublishLicenseStreamHeaderTooLong, headerLen…
- SR.VersionUpdateFailure
- Document contains multiple Rights Management Encryption…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/d7d12ad47e745fdf.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs:125
// 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.
// TODO: Use leaveOpen ctor
BinaryReader utf8Reader = new BinaryReader(_publishLicenseStream, Encoding.UTF8);
//
// There follows a variable-length header (not to be confused with the physical
// stream header). This header allows future expansion, in case we want to store
// something in addition to the publish license in the primary instance data stream
// for this transform. The first field in the header is the header length in bytes
// (including the headerLen field itself).
//
Int32 headerLen = utf8Reader.ReadInt32();
if (headerLen < CU.Int32Size)
{
throw new FileFormatException(SR.PublishLicenseStreamCorrupt);
}
if (headerLen > MaxPublishLicenseHeaderLen)
{
throw new FileFormatException(
SR.Format(SR.PublishLicenseStreamHeaderTooLong,
headerLen,
MaxPublishLicenseHeaderLen
));
}
//
// Save any additional bytes in the header that we don't recognize, so we can
// write them back out later if necessary. We've already read the headerLen field,
// so subtract the size of that field from the amount we have to save.
//
// No need to use checked{} here since we already made sure that header length is greater than Int32Size
Int32 numPublishLicenseHeaderExtraBytes = headerLen - CU.Int32Size;View on GitHub (pinned to 81131a70a4)