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
- Load the ISF with a runtime/version that recognizes the tag's GUID, or upgrade to the newest WPF/System.Windows.Ink implementation
- Strip unknown extended properties before saving so only well-known GUID tags are embedded
- Use DrawAttributes/extended properties only with GUIDs from KnownValues/AnalysisCore GUID tables when targeting cross-version ISF
- Catch ArgumentException, and re-persist the ink from the in-memory StrokeCollection (losing the unknown property)
- 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
- Only embed extended properties with GUIDs from the known GUID table when cross-version compatibility matters
- Avoid round-tripping ISF between different vendors' ink SDKs
- Version-tag your ink files so unknown producers can be detected before load
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
- Drawing Attribute tag embedded in ISF stream does not match…
- Buffer range is smaller than expected expected size
- Button data length not equal to expected length
- Empty data to load
- ExtendedProperty decoded totalBytesInStrokeBlockOfIsfStream…
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)