dotnet/wpf · error · ArgumentException

Button data length not equal to expected length

Error message

Button data length not equal to expected length

What it means

Thrown by StrokeSerializer.LoadPackets after unpacking per-packet button bits: the number of bytes actually accumulated (byteCounter) does not match the pre-allocated buttonData.Length. This is a post-decode consistency check confirming the ISF button section was well-formed.

Solutions

  1. Regenerate the ISF stream with StrokeCollection.Save and reload
  2. Verify no byte-level transformation (encoding, compression) altered the stream between save and load
  3. Use matching .NET Framework/WPF versions on both ends
  4. Catch ArgumentException during decode and skip invalid strokes
Defensive patterns

Strategy: try-catch

Validate before calling

// Round-trip test the ISF before trusting it
var ms = new MemoryStream(); strokeCollection.Save(ms); // valid baseline

Try / catch

try { DecodeISFIntoStroke(isfStream); }
catch (ArgumentException ex) { MessageBox.Show("Ink data is corrupted: " + ex.Message); }

Prevention

When it happens

Trigger: DecodeISFIntoStroke reads button bits whose packed/unpacked byte counts disagree — internal inconsistency in the ISF stream's button descriptors.

Common situations: ISF streams from incompatible ink runtimes, corrupted clipboard ink data, streams altered after serialization.

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


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/e3fc73224bbbe2eb. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/StrokeSerializer.cs:518

                int byteCounter = 0;
                while (!bitReader.EndOfStream)
                {
                    // unpack the fully bytes first
                    for (int fullBytes = 0; fullBytes < fullBytesForButtonsPerPacket; fullBytes++)
                    {
                        buttonData[byteCounter++] = bitReader.ReadByte(Native.BitsPerByte);
                    }
                    // then unpack a single partial byte if necessary
                    if (partialBitsForButtonsPerPacket > 0)
                    {
                        buttonData[byteCounter++] = bitReader.ReadByte((int)partialBitsForButtonsPerPacket);
                    }
                }

                // if the number of bytes allocated != necessary byte amount then an error occurred
                if (byteCounter != buttonData.Length)
                {
                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Button data length not equal to expected length"));
                }

                //
                // set the point data in the raw array
                //
                FillButtonData( (int)pointCount,
                                buttonCount,
                                valueIntsPerPoint, //gives the first button index
                                rawPointData,
                                buttonData);
            }


            stylusPoints = new StylusPointCollection(stylusPointDescription, rawPointData, null, transform);

            // if we read too far into the stream (e.g. the packets were compressed)
            //      then move the stream pointer back to the end of the actual packet
            //      data before returning. This keeps the return value on the function

View on GitHub (pinned to 81131a70a4)