SixLabors/ImageSharp · error · NotSupportedException
Matrix is singular and cannot be solve
Error message
Matrix is singular and cannot be solve
What it means
GaussianEliminationSolver.TransformToRowEchelonForm solves linear systems via Gaussian elimination; if it cannot find a nonzero pivot in a column, the matrix is singular and the system has no unique solution. Since NotSupportedException conveys 'this operation cannot proceed', the solver aborts rather than returning garbage.
Solutions
- Provide 4 non-degenerate (non-collinear, distinct) source/destination point pairs
- Deduplicate and validate control points before building the transform
- Catch NotSupportedException from Solve and fall back to an affine transform, which needs fewer points
- If points come from feature detection, apply an epsilon check on the area of the quad formed by the points
Example fix
// before
var matrix = ProjectiveTransformBuilder.DefineQuad(sourcePoints, destPoints); // collinear points
// after
static bool IsValidQuad(PointF[] p) =>
Math.Abs(((p[1].X - p[0].X) * (p[2].Y - p[0].Y)) - ((p[2].X - p[0].X) * (p[1].Y - p[0].Y))) > float.Epsilon;
if (!IsValidQuad(sourcePoints) || !IsValidQuad(destPoints))
{
throw new InvalidOperationException("Projective transform requires non-collinear points.");
}
var matrix = ProjectiveTransformBuilder.DefineQuad(sourcePoints, destPoints); Defensive patterns
Strategy: validation
Validate before calling
static float QuadArea(PointF a, PointF b, PointF c, PointF d) =>
MathF.Abs((b.X - a.X) * (c.Y - a.Y) - (c.X - a.X) * (b.Y - a.Y))
+ MathF.Abs((c.X - a.X) * (d.Y - a.Y) - (d.X - a.X) * (c.Y - a.Y));
if (QuadArea(p0, p1, p2, p3) < 1e-3f) throw new InvalidOperationException("Points are degenerate/collinear."); Type guard
static bool ArePointsDistinctAndNonCollinear(PointF[] pts) =>
pts.Length == 4
&& pts.Distinct().Count() == 4
&& MathF.Abs((pts[1].X - pts[0].X) * (pts[2].Y - pts[0].Y) - (pts[2].X - pts[0].X) * (pts[1].Y - pts[0].Y)) > float.Epsilon; Try / catch
try
{
var m = ProjectiveTransformBuilder.DefineQuad(src, dst);
}
catch (NotSupportedException ex) when (ex.Message.Contains("singular"))
{
// fall back to affine transform or request better point correspondences
} Prevention
- Provide 4 distinct, non-collinear source and destination points
- Deduplicate points before building projective transforms
- When points come from feature detection, verify they form a quad with non-zero area
- Consider falling back to affine transforms when only 3 reliable correspondences exist
When it happens
Trigger: Calling Solve (used by ProjectiveTransformBuilder to derive projective matrices from point correspondences) with degenerate/ collinear control points so the elimination hits a zero pivot column.
Common situations: Using ProjectiveTransformBuilder with 4 coplanar/collinear source points; supplying duplicate destination points; computing transforms from auto-detected corner points that are degenerate (e.g. straight-line feature matches).
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
AI-assisted analysis of SixLabors/ImageSharp@59ce6af6fc (2026-09-13).
Data as JSON: /api/errors/c2a446b22dd88fb0.
Report an issue: GitHub.
Appendix: source
Thrown at src/ImageSharp/Processing/Processors/Transforms/Linear/GaussianEliminationSolver.cs:50
int rowCount = matrix[0].Length;
int pivotRow = 0;
for (int pivotCol = 0; pivotCol < colCount; pivotCol++)
{
double maxValue = double.Abs(matrix[pivotRow][pivotCol]);
int maxIndex = pivotRow;
for (int r = pivotRow + 1; r < rowCount; r++)
{
double value = double.Abs(matrix[r][pivotCol]);
if (value > maxValue)
{
maxIndex = r;
maxValue = value;
}
}
if (matrix[maxIndex][pivotCol] == 0)
{
throw new NotSupportedException("Matrix is singular and cannot be solve");
}
(matrix[pivotRow], matrix[maxIndex]) = (matrix[maxIndex], matrix[pivotRow]);
(result[pivotRow], result[maxIndex]) = (result[maxIndex], result[pivotRow]);
for (int r = pivotRow + 1; r < rowCount; r++)
{
double fraction = matrix[r][pivotCol] / matrix[pivotRow][pivotCol];
for (int c = pivotCol + 1; c < colCount; c++)
{
matrix[r][c] -= matrix[pivotRow][c] * fraction;
}
result[r] -= result[pivotRow] * fraction;
matrix[r][pivotCol] = 0;
}
pivotRow++;View on GitHub (pinned to 59ce6af6fc)