dotnet/wpf · error · ArgumentException

Stroke Custom Attribute tag embedded in ISF stream does not…

Error message

Stroke Custom Attribute tag embedded in ISF stream does not match guid table

What it means

Thrown by StrokeSerializer.DecodeISFIntoStroke when a custom-attribute tag read from the ISF stream cannot be resolved to a Guid via the GuidList (guid table). Every embedded extended property tag must map to a known GUID; an unmapped tag means the stream was produced by an unknown/incompatible ISF writer or is corrupt.

Solutions

  1. Load the ISF with a runtime/version that recognizes the tag's GUID, or upgrade to the newest WPF/System.Windows.Ink implementation
  2. Strip unknown extended properties before saving so only well-known GUID tags are embedded
  3. Use DrawAttributes/extended properties only with GUIDs from KnownValues/AnalysisCore GUID tables when targeting cross-version ISF
  4. Catch ArgumentException, and re-persist the ink from the in-memory StrokeCollection (losing the unknown property)
  5. Inspect the ISF with a hex dump to identify the offending tag and confirm the producer application

Example fix

// before
stroke.AddPropertyData(customVendorGuid, data); // unknown to other readers' guid table
// after
if (KnownValues.GetAllKnownGuids().Contains(customVendorGuid))
    stroke.AddPropertyData(customVendorGuid, data); // only embed known GUIDs
Defensive patterns

Strategy: try-catch

Validate before calling

// Restrict embedded extended properties to known GUIDs before saving
static bool IsKnownGuid(Guid g) =>
    g == KnownValues.StrokeExtendedPropertyGuid || /* ...other known GUIDs... */ false;
// filter: keep only strokes whose ExtendedProperties keys are known

Try / catch

try { scs.Deserialize(stream); }
catch (ArgumentException ex) when (ex.Message.Contains("does not match guid table")) {
    log.Warn("Unknown ISF custom-attribute tag", ex);
    // re-persist ink from object model without unknown properties
}

Prevention

When it happens

Trigger: Deserializing ISF that contains stroke extended-property tags not present in the reader's GUID table (ISF from other vendors, proprietary extensions, or bit-corrupted tag values) via StrokeCollection.Deserialize.

Common situations: Round-tripping ink between different vendors' ink SDKs; loading ISF written by newer WPF versions carrying GUIDs unknown to an older reader; corrupted tag bytes in damaged files.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

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

                                byte[] out_buffer = Compressor.DecompressPropertyData(in_buffer);

                                System.Diagnostics.Debug.Fail("ExtendedProperties for points are not supported");

                                // skip the bytes in both success & failure cases
                                // Note: Point ExtendedProperties are discarded
                                remainingBytesInStrokeBlock -= propsize;
                            }
                        }
                        break;

                    default:
                        {
                            object data;
                            Guid guid = guidList.FindGuid(tag);
                            if (guid == Guid.Empty)
                            {
                                throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Stroke Custom Attribute tag embedded in ISF stream does not match guid table"));
                            }

                            // load the extended property data from the stream (and decode the type)
                            locallyDecodedBytes = ExtendedPropertySerializer.DecodeAsISF(stream, remainingBytesInStrokeBlock, guidList, tag, ref guid, out data);

                            // add the guid/data pair into the property collection (don't redecode the type)
                            if (extendedProperties == null)
                            {
                                extendedProperties = new ExtendedPropertyCollection();
                            }
                            extendedProperties[guid] = data;
                            if (locallyDecodedBytes > remainingBytesInStrokeBlock)
                            {
                                throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ExtendedProperty decoded totalBytesInStrokeBlockOfIsfStream exceeded ISF stream totalBytesInStrokeBlockOfIsfStream"));
                            }

                            remainingBytesInStrokeBlock -= locallyDecodedBytes;
                        }

View on GitHub (pinned to 81131a70a4)