{"record":{"id":"d7d12ad47e745fdf","repo":"dotnet/wpf","slug":"sr-publishlicensestreamcorrupt","errorCode":null,"errorMessage":"SR.PublishLicenseStreamCorrupt","messagePattern":"SR\\.PublishLicenseStreamCorrupt","errorType":"exception","errorClass":"FileFormatException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs","lineNumber":125,"sourceCode":"            // does -not- close the underlying stream.\n            //\n\n            // The stream is not owned by the BlockManager, therefore we cannot \n            // close the BinaryWriter, as that would Close the stream underneath.\n            // TODO: Use leaveOpen ctor\n            BinaryReader utf8Reader = new BinaryReader(_publishLicenseStream, Encoding.UTF8);\n\n            //\n            // There follows a variable-length header (not to be confused with the physical\n            // stream header). This header allows future expansion, in case we want to store\n            // something in addition to the publish license in the primary instance data stream\n            // for this transform. The first field in the header is the header length in bytes\n            // (including the headerLen field itself).\n            //\n            Int32 headerLen = utf8Reader.ReadInt32();\n            if (headerLen < CU.Int32Size)\n            {\n                throw new FileFormatException(SR.PublishLicenseStreamCorrupt);\n            }\n\n            if (headerLen > MaxPublishLicenseHeaderLen)\n            {\n                throw new FileFormatException(\n                                SR.Format(SR.PublishLicenseStreamHeaderTooLong,\n                                headerLen,\n                                MaxPublishLicenseHeaderLen\n                                ));\n            }\n\n            //\n            // Save any additional bytes in the header that we don't recognize, so we can\n            // write them back out later if necessary. We've already read the headerLen field,\n            // so subtract the size of that field from the amount we have to save.\n            //\n            // No need to use checked{} here since we already made sure that header length is greater than Int32Size\n            Int32 numPublishLicenseHeaderExtraBytes = headerLen - CU.Int32Size;","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs#L107-L143","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: blindly opening a suspect file\nvar publishLicense = new PublishLicense(rmStreamData);\n\n// after: validate the length prefix first\nint headerLen = ReadInt32AtStart(rmStreamData);\nif (headerLen < sizeof(int))\n{\n    throw new InvalidDataException(\n        \"Publish license header length is invalid; the protected document is corrupt.\");\n}\nvar publishLicense = new PublishLicense(rmStreamData);","handlingStrategy":"validation","validationCode":"// peek the header length before attempting to load\nstream.Seek(0, SeekOrigin.Begin);\nSpan<byte> buf = stackalloc byte[4];\nif (stream.Read(buf) < 4 || BitConverter.ToInt32(buf) < sizeof(int))\n    throw new InvalidDataException(\"Publish license header length invalid; file is corrupt.\");","typeGuard":"static bool HasValidLicenseHeader(Stream s)\n{\n    long pos = s.Position;\n    Span<byte> b = stackalloc byte[4];\n    bool ok = s.Read(b) == 4 && BitConverter.ToInt32(b) >= 4;\n    s.Seek(pos, SeekOrigin.Begin);\n    return ok;\n}","tryCatchPattern":"try\n{\n    publishLicense = transform.LoadPublishLicense();\n}\ncatch (FileFormatException ex)\n{\n    log.Error(\"Publish license header corrupt in protected document\", ex);\n    throw new InvalidDataException(\"Protected document is corrupt; restore from a good copy.\", ex);\n}","preventionTips":["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."],"tags":["wpf","packaging","rights-management","file-format","data-corruption"],"backgroundTag":"schema-validation-failed","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}