{"record":{"id":"878a808de151ad77","repo":"dotnet/wpf","slug":"sr-versionupdatefailure","errorCode":null,"errorMessage":"SR.VersionUpdateFailure","messagePattern":"SR\\.VersionUpdateFailure","errorType":"exception","errorClass":"FileFormatException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/VersionedStreamOwner.cs","lineNumber":353,"sourceCode":"        /// then only the Updater field is modified.\n        /// </remarks>\n        private void PersistVersion(FormatVersion version)\n        {\n            if (!BaseStream.CanWrite)\n                throw new NotSupportedException(SR.WriteNotSupported);\n\n            // normalize and save\n            long tempPos = checked(BaseStream.Position - _dataOffset);\n            BaseStream.Seek(0, SeekOrigin.Begin);\n\n            // update _dataOffset\n            long offset = version.SaveToStream(BaseStream);\n            _fileVersion = version;     // we know what it is - no need to deserialize\n\n            // existing value - ensure we didn't change sizes as this could lead to\n            // data corruption\n            if ((_dataOffset != 0) && (offset != _dataOffset))\n                throw new FileFormatException(SR.VersionUpdateFailure);\n\n            // at this point we know the offset\n            _dataOffset = offset;\n\n            // restore and shift\n            checked { BaseStream.Position = tempPos + _dataOffset; }\n        }\n\n        /// <summary>\n        /// Load and compare feature identifier\n        /// </summary>\n        /// <remarks>There is no need for this method to maintain any previous Seek pointer.\n        /// This method only modifies the stream position when called for the first time with a non-empty\n        /// stream.  It is always called from Seek() and set_Position, which subsequently modify the stream\n        /// pointer as appropriate after the call.</remarks>\n        private void EnsureParsed()\n        {\n            // empty stream cannot have a version in it","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/VersionedStreamOwner.cs#L335-L371","documentation":"VersionedStreamOwner.PersistVersion writes the compression transform version header to the underlying compound-file stream. If a version header already exists (_dataOffset != 0) but the newly serialized header has a different size, the stream layout would shift and corrupt data, so a FileFormatException is thrown.","triggerScenarios":"Calling WriteAttempt on a VersionedStreamOwner whose stream already contains a version header, where version.SaveToStream(BaseStream) returns an offset different from the stored _dataOffset (header size changed between write and rewrite).","commonSituations":"Editing an existing compressed XPS/compound-file stream with a different framework or library version that emits a different-length version header; hand-modified or truncated package files; partial writes by another tool.","solutions":["Rewrite the whole container/stream instead of updating the version header in place (e.g. recreate the package).","Ensure the same .NET/WPF version and transform that originally produced the file is used to update it.","Verify the file was not truncated or edited by external tools; restore from a known-good copy.","If this recurs after a framework upgrade, regenerate all packages with the new runtime rather than patching old ones."],"exampleFix":"// before: updating version header in place on an existing stream\nversionedStream.Write(newHeaderData, 0, newHeaderData.Length);\n// after: recreate the stream/package when the header layout may differ\nusing (var newPackage = Package.Open(newPath, FileMode.Create))\n{\n    CopyPackageContents(oldPackage, newPackage);\n}","handlingStrategy":"validation","validationCode":"// before updating, confirm the stream either has no version header or will keep its layout\nif (existingDataOffset != 0)\n{\n    long newSize = version.SaveToStream(probeStream); // measure on a scratch stream\n    if (newSize != existingDataOffset)\n        throw new InvalidOperationException(\"Version header size changed; recreate the package instead of updating in place\");\n}","typeGuard":null,"tryCatchPattern":"try { owner.WriteAttempt(buffer, 0, len); }\ncatch (FileFormatException e) { logger.Warn(e, \"Header size changed; rebuilding package\"); RecreatePackage(sourcePath, destPath); }","preventionTips":["Pin the runtime/tool version used to write and update compound-file packages","Never hand-edit version headers with external tools","Regenerate packages wholesale rather than patching headers in place"],"tags":["wpf","packaging","compound-file","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"}