dotnet/wpf · error · InvalidOperationException

Empty data to load

Error message

Empty data to load

What it means

Thrown by CustomAttributeSerializer.DecodeAsISF when asked to decode an ISF custom-attribute payload whose total byte size (cbSize) is zero. There is no attribute data to read, so decoding is impossible. This guards the deserializer against empty or truncated streams.

Solutions

  1. Check that the ISF data/byte array is non-empty before attempting Load/DecodeAsISF.
  2. Verify the source file or stream actually contains ink data (length > 0) and was not truncated.
  3. Re-export or re-save the ink data from the original source.
  4. If the empty payload is expected/allowed, skip decoding instead of calling the decoder.

Example fix

// before
if (attributeData != null) attr = CustomAttributeSerializer.DecodeAsISF(attributeData, 0, stream, ...);
// after
if (attributeData != null && attributeData.Length > 0) attr = CustomAttributeSerializer.DecodeAsISF(attributeData, 0, stream, ...);
Defensive patterns

Strategy: validation

Validate before calling

if (data == null || data.Length == 0) throw new InvalidDataException("ISF attribute data is empty; skipping decode");

Type guard

bool HasIsfPayload(byte[] data) => data is { Length: > 0 };

Try / catch

try { attr = DecodeAsISF(data, 0, stream, size, tag, out guid); }
catch (InvalidOperationException) { attr = null; /* empty payload */ }

Prevention

When it happens

Trigger: Calling DecodeAsISF (via ExtendedProperties deserialization, e.g. StrokeCollection Load from ISF) with a zero-length byte array, or passing cbSize=0 for an attribute recovered from a stream.

Common situations: Loading ink from a file that was saved empty or truncated; passing a MemoryStream constructed from an empty byte[]; reading an attribute block whose recorded size is 0 due to earlier corruption.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/CustomAttributeSerializer.cs:411

        /// the case of Stroke ExtendedPropertyCollection where tag is stored in the stroke descriptor or 0 when tag
        /// is embeded in the stream
        /// </summary>
        /// <param name="stream">Memory buffer to load from</param>
        /// <param name="cbSize">Maximum length of buffer to read</param>
        /// <param name="guidList">Guid cache to read from</param>
        /// <param name="tag">Guid tag to lookup</param>
        /// <param name="guid">Guid of property</param>
        /// <param name="data">Data of property</param>
        /// <returns>Length of buffer read</returns>
#endif
        internal static uint DecodeAsISF(Stream stream, uint cbSize, GuidList guidList, KnownTagCache.KnownTagIndex tag, ref Guid guid, out object data)
        {
            uint cb, cbRead = 0;
            uint cbTotal = cbSize;

            if (0 == cbSize)
            {
                throw new InvalidOperationException(SR.EmptyDataToLoad);
            }

            if (0 == tag) // no tag is passed, it must be embedded in the data
            {
                uint uiTag;
                cb = SerializationHelper.Decode(stream, out uiTag);
                tag = (KnownTagCache.KnownTagIndex)uiTag;
                if (cb > cbTotal)
                    throw new ArgumentException(SR.InvalidSizeSpecified, nameof(cbSize));

                cbTotal -= cb;
                cbRead += cb;
                System.Diagnostics.Debug.Assert(guid == Guid.Empty);
                guid = guidList.FindGuid(tag);
            }

            if (guid == Guid.Empty)
            {

View on GitHub (pinned to 81131a70a4)