dotnet/wpf · error · InvalidOperationException
ROP data was incorrectly serialized
Error message
ROP data was incorrectly serialized
What it means
Thrown by PersistRasterOperation after writing the RasterOperation value: the number of bytes actually written to the stream differs from ropSize reported by GetDataSizeIfKnownGuid. The serializer keeps the size table in sync with what it writes, so a mismatch means the writer wrote the wrong amount of data for the ROP value — an internal serialization invariant violation.
Solutions
- Ensure any RasterOperation entry added to the GuidList declares the correct size (4 bytes for the standard ROP value).
- Avoid manual manipulation of the GuidList / ISF internals; use the public StrokeCollection.Save API.
- Reset DrawingAttributes to standard values (default RasterOperation) before saving to skip the ROP path entirely.
- Catch InvalidOperationException around Save and re-throw with the drawing attributes for diagnostics.
Example fix
// before: custom size registered wrongly guidList.Add(KnownIds.RasterOperation, size: 2); // after: standard ROP value is 4 bytes guidList.Add(KnownIds.RasterOperation, size: 4);
Defensive patterns
Strategy: try-catch
Validate before calling
Debug.Assert(guidList.GetDataSizeIfKnownGuid(KnownIds.RasterOperation) == 4, "RasterOperation data size must be 4 bytes");
Type guard
bool HasValidRopSize(GuidList g) => g.GetDataSizeIfKnownGuid(KnownIds.RasterOperation) == 4;
Try / catch
try { collection.Save(stream); }
catch (InvalidOperationException ex) when (ex.Message.Contains("ROP data was incorrectly serialized")) { /* regenerate GuidList or reset attributes */ } Prevention
- Do not manually modify the GuidList or ISF internals.
- Keep RasterOperation at its default unless the full V1 encoding path is exercised.
- Round-trip test Save/Load in CI to catch serialization drift early.
When it happens
Trigger: EncodeAsISF on DrawingAttributes whose RasterOperation value serializes to a byte count different from the size the GuidList associates with the RasterOperation GUID — typically caused by corrupt/modified GuidList state or custom ROP data inserted with a wrong size.
Common situations: Custom ISF code that registered a RasterOperation data size inconsistent with the 4-byte value the serializer writes; debugging/patching internals of the ink serialization stack.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Invalid EP in ISF
- Packed button length not equal to expected length
- Property data must be a non-reference variant compatible…
- Read different size from stream then expected
- Tag is outside of the known guid tag range
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/1abc0d4a5126e2ba.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/DrawingAttributeSerializer.cs:541
private static void PersistRasterOperation(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw)
{
// write any non-default RasterOp value that we might have picked up from
// V1 interop or by setting IsHighlighter.
if (da.RasterOperation != DrawingAttributeSerializer.RasterOperationDefaultV1)
{
uint ropSize = GuidList.GetDataSizeIfKnownGuid(KnownIds.RasterOperation);
if (ropSize == 0)
{
throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data size was not found"));
}
Debug.Assert(bw != null);
cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.RasterOperation, true));
long currentPosition = stream.Position;
bw.Write(da.RasterOperation);
if ((uint)(stream.Position - currentPosition) != ropSize)
{
throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data was incorrectly serialized"));
}
cbData += ropSize;
}
}
#if OLD_ISF
/// <Summary>
/// Encodes the ExtendedProperties in the ISF stream.
/// </Summary>
#else
/// <Summary>
/// Encodes the ExtendedProperties in the ISF stream.
/// </Summary>
#endif
private static void PersistExtendedProperties(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw, byte compressionAlgorithm, bool fTag)
{
// Now save the extended properties
ExtendedPropertyCollection epcClone = da.CopyPropertyData();
View on GitHub (pinned to 81131a70a4)