{"record":{"id":"23752204ba669a9a","repo":"dotnet/wpf","slug":"sr-packagecontrollerstreamcorruption","errorCode":null,"errorMessage":"SR.PackageControllerStreamCorruption","messagePattern":"SR\\.PackageControllerStreamCorruption","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"critical","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/Documents/Application/PackageController.cs","lineNumber":123,"sourceCode":"    bool IDocumentController.SaveCommit(Document document)\n    {\n        PackageDocument doc = (PackageDocument)document;\n\n        if (doc.Destination == null)\n        {\n            return false;\n        }\n\n        if (doc.Package.IsDirty || !doc.IsDestinationIdenticalToSource)\n        {\n            StreamProxy source = doc.Source as StreamProxy;\n            StreamProxy destination = doc.Destination as StreamProxy;\n\n            // this will catch the case where our source stream is our destination\n            // stream, which would cause corruption of the package\n            if (source.GetHashCode() == destination.GetHashCode())\n            {\n                throw new InvalidOperationException(\n                    SR.PackageControllerStreamCorruption);\n            }\n\n            // this will catch the case where no one was able to copy the stream\n            // thus the lengths will not match\n            if (doc.Source.Length != doc.Destination.Length)\n            {\n                throw new InvalidOperationException(\n                    SR.PackageControllerStreamCorruption);\n            }\n\n            // Flush the package to ensure that the relationship parts are\n            // written out before changes are merged\n            doc.Package.Flush();\n\n            doc.Package.MergeChanges(doc.Destination);\n            Trace.SafeWrite(Trace.File, \"Destination Merged.\");\n        }","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/Documents/Application/PackageController.cs#L105-L141","documentation":"PackageController.SaveCommit throws InvalidOperationException with SR.PackageControllerStreamCorruption when the source and destination streams are the same object (detected via equal hash codes), which would corrupt the package, and also when the copy failed (source and destination lengths differ). It is a safety check protecting package integrity during commit.","triggerScenarios":"Saving a document where doc.Destination is a StreamProxy wrapping the same underlying stream as doc.Source; or where no registered copier succeeded so Destination.Length != Source.Length at commit time.","commonSituations":"Programming mistakes where save target and source reference the same stream; stream types unsupported by any copier causing a truncated/incomplete copy; an earlier IO error leaving the destination partially written.","solutions":["Ensure the save destination is a different stream than the source; open a new FileStream/StreamProxy for the target.","Check that the destination stream supports writing and was fully written; compare lengths before commit.","If a copier failed, fix the underlying IO error (permissions, disk space, stream capabilities) and retry the save.","Dispose/reopen the document cleanly instead of committing from a partially copied package."],"exampleFix":"// before\nStreamProxy dest = new StreamProxy(sourceStream); // same stream as source\npackageController.SaveCommit(doc);\n// after\nvar dest = new StreamProxy(new FileStream(targetPath, FileMode.Create, FileAccess.Write));\npackageController.SaveCommit(doc);","handlingStrategy":"validation","validationCode":"bool safeToCommit = !ReferenceEquals(doc.Source, doc.Destination) && doc.Source.Length == doc.Destination.Length;","typeGuard":null,"tryCatchPattern":"try { packageController.SaveCommit(doc); }\ncatch (InvalidOperationException) { /* reopen document; do not commit partial copy */ }","preventionTips":["Never pass the same stream as both source and save destination.","Verify the destination stream supports writing and was fully copied before commit.","Resolve underlying IO errors (space, permissions) before retrying saves."],"tags":["xps","package","corruption","invalid-operation","stream"],"backgroundTag":"internal-invariant-violation","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"}