dotnet/wpf · error · ArgumentException
SR.InvalidMatrixContainsNaN
Error message
SR.InvalidMatrixContainsNaN
What it means
Stroke.Transform(Matrix) rejects matrices containing NaN values via MatrixHelper.ContainsNaN. A NaN matrix has no meaningful geometric interpretation and would corrupt cached geometry and bounds, so an ArgumentException naming transformMatrix is thrown before any state is modified.
Solutions
- Validate with MatrixHelper.ContainsNaN (or double.IsNaN on M11..OffsetY) before calling Transform and reject/repair the source values
- Trace upstream arithmetic (divisions, layout values) that produce NaN and fix at the source
- Replace the NaN matrix with a valid default (e.g. Matrix.Identity) when NaN indicates missing data
Example fix
// before
stroke.Transform(computedMatrix); // may contain NaN
// after
if (!MatrixHelper.ContainsNaN(computedMatrix) && !MatrixHelper.ContainsInfinity(computedMatrix))
stroke.Transform(computedMatrix); Defensive patterns
Strategy: validation
Validate before calling
bool ok = !MatrixHelper.ContainsNaN(matrix) && !MatrixHelper.ContainsInfinity(matrix) && matrix.HasInverse;
Type guard
bool IsFiniteMatrix(Matrix m) => double.IsFinite(m.M11) && double.IsFinite(m.M12) && double.IsFinite(m.M21) && double.IsFinite(m.M22) && double.IsFinite(m.OffsetX) && double.IsFinite(m.OffsetY);
Prevention
- Trace NaN sources upstream: division by zero, NaN layout values (ActualWidth during layout)
- Reject non-finite computed transforms at the boundary where they are built
- Test transform math with edge-case inputs (zero sizes)
When it happens
Trigger: Calling stroke.Transform(m) where any of m's six doubles is NaN — typically the result of 0/0, Math.Atan of invalid input, or a transform derived from a divide-by-zero scale computation.
Common situations: Data-binding or measurement code producing NaN widths/heights (e.g. NaN from ActualWidth before layout) that flow into matrix construction; deserializing matrices from corrupted data.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- InvalidMatrixContainsNaN
- SR.InvalidMatrixContainsInfinity
- SR.MatrixNotInvertible
- InvalidMatrixContainsInfinity
- MatrixNotInvertible
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/83065030155eb5ba.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Ink/Stroke.cs:148
/// <summary>Transforms the ink and also changes the StylusTip</summary>
/// <param name="transformMatrix">Matrix to transform the stroke by</param>
/// <param name="applyToStylusTip">Boolean if true the transform matrix will be applied to StylusTip</param>
public virtual void Transform(Matrix transformMatrix, bool applyToStylusTip)
{
if (transformMatrix.IsIdentity)
{
return;
}
if (!transformMatrix.HasInverse)
{
throw new ArgumentException(SR.MatrixNotInvertible, nameof(transformMatrix));
}
else if ( MatrixHelper.ContainsNaN(transformMatrix))
{
throw new ArgumentException(SR.InvalidMatrixContainsNaN, nameof(transformMatrix));
}
else if ( MatrixHelper.ContainsInfinity(transformMatrix))
{
throw new ArgumentException(SR.InvalidMatrixContainsInfinity, nameof(transformMatrix));
}
else
{
// we need to force a recaculation of the cached path geometry right after the
// DrawingAttributes changed, beforet the events are raised.
_cachedGeometry = null;
// Set the cached bounds to empty, which will force a re-calculation of the _cachedBounds upon next GetBounds call.
_cachedBounds = Rect.Empty;
if (applyToStylusTip)
{
//we use this flag to prevent this method from causing two
//invalidates, which causes a good deal of memory thrash when
//the strokes are being renderedView on GitHub (pinned to 81131a70a4)