dotnet/wpf · error · InvalidOperationException
ISF decoder cannot operate on non-empty ink container
Error message
ISF decoder cannot operate on non-empty ink container
What it means
DecodeRawISF requires the target ink container to be empty before decoding; if _coreStrokes already contains strokes or extended properties, it throws InvalidOperationException. The ISF decoder overwrites the container and refuses to merge into existing ink, so reusing a populated StrokeCollection's internal container is unsupported.
Solutions
- Create a fresh StrokeCollection/InkSerializer for each decode operation
- Clear extended properties and strokes (or use a new instance) before decoding
- Decode into a temporary collection and merge afterwards if combining ink is needed
Example fix
// before serializer.DecodeISF(stream1); serializer.DecodeISF(stream2); // throws // after var s1 = new StrokeCollectionSerializer(); s1.DecodeISF(stream1); var s2 = new StrokeCollectionSerializer(); s2.DecodeISF(stream2); var combined = new StrokeCollection(s1.Strokes.Concat(s2.Strokes));
Defensive patterns
Strategy: type-guard
Validate before calling
// only decode into fresh containers bool CanDecode(StrokeCollection c) => c.Count == 0 && c.ExtendedProperties.Count == 0;
Type guard
bool IsEmptyInkContainer(StrokeCollection c) => c.Count == 0 && c.ExtendedProperties.Count == 0;
Try / catch
try { serializer.DecodeISF(stream); }
catch (InvalidOperationException) { serializer = new StrokeCollectionSerializer(); serializer.DecodeISF(stream); } Prevention
- Instantiate a new StrokeCollection/serializer per document
- Never reuse a populated collection as a decode target
- Merge collections after decoding instead of decoding into existing ink
When it happens
Trigger: Calling DecodeISF (directly or via StrokeCollectionSerializer) on an InkSerializer whose stroke collection already holds strokes or extended properties — e.g. decoding into a loaded collection a second time.
Common situations: Reusing a single StrokeCollection/serializer instance to load multiple ink documents, calling DecodeISF twice on the same object, appending persisted ink to an already-populated collection.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Buffer range is smaller than expected expected size
- Button data length not equal to expected length
- Cannot initialize compressor.
- Decompression of packet data failed.
- Drawing Attribute tag embedded in ISF stream does not match…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/14af4cbe498de345.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/InkSerializer.cs:324
uint metricDescriptorTableIndex = 0;
uint oldMetricDescriptorTableIndex = 0xFFFFFFFF;
uint transformTableIndex = 0;
uint oldTransformTableIndex = 0xFFFFFFFF;
GuidList guidList = new GuidList();
int strokeIndex = 0;
StylusPointDescription currentStylusPointDescription = null;
Matrix currentTabletToInkTransform = Matrix.Identity;
_strokeDescriptorTable = new System.Collections.Generic.List<StrokeDescriptor>();
_drawingAttributesTable = new System.Collections.Generic.List<DrawingAttributes>();
_transformTable = new System.Collections.Generic.List<TransformDescriptor>();
_metricTable = new System.Collections.Generic.List<MetricBlock>();
// First make sure this ink is empty
if (0 != _coreStrokes.Count || _coreStrokes.ExtendedProperties.Count != 0)
{
throw new InvalidOperationException(ISFDebugMessage("ISF decoder cannot operate on non-empty ink container"));
}
#if OLD_ISF
//
// store a compressor reference at this scope, if it is needed (if there is a compresson header) and
// therefore instanced during this routine, we will dispose of it
// in the finally block
//
Compressor compressor = null;
try
{
#endif
// First read the isfTag
uint uiTag;
uint localBytesDecoded = SerializationHelper.Decode(inputStream, out uiTag);
if (0x00 != uiTag)
throw new ArgumentException(SR.InvalidStream);View on GitHub (pinned to 81131a70a4)