SixLabors/ImageSharp · error · DegenerateTransformException

Matrix is degenerate. Check input values.

Error message

Matrix is degenerate. Check input values.

What it means

The ProjectiveTransformProcessor constructor validates that the 4x4 projective matrix is non-degenerate — a degenerate matrix collapses the projective plane and produces an unrenderable mapping. TransformUtilities.IsDegenerate guards this in the constructor, throwing DegenerateTransformException before sampling starts.

Solutions

  1. Check Matrix4x4.GetDeterminant() before constructing the processor
  2. Correct or clamp the matrix values that produce the degenerate result
  3. Catch DegenerateTransformException and substitute a fallback (identity or affine) transform
  4. When building matrices from points, ensure they form a proper quad with non-zero area

Example fix

// before
var m = new Matrix4x4(
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 0, 0, // last row zeroed => degenerate
    0, 0, 0, 1);
image.Mutate(x => x.Transform(new ProjectiveTransformBuilder().AppendMatrix(m)));
// after
var m = new Matrix4x4(
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1); // ensure non-zero determinant
image.Mutate(x => x.Transform(new ProjectiveTransformBuilder().AppendMatrix(m)));
Defensive patterns

Strategy: validation

Validate before calling

static bool IsNonDegenerate(Matrix4x4 m) => MathF.Abs(m.GetDeterminant()) > 1e-6f;
if (!IsNonDegenerate(matrix)) throw new InvalidOperationException("Projective matrix is degenerate.");

Type guard

static bool IsUsableProjectiveMatrix(Matrix4x4 m) => !float.IsNaN(m.GetDeterminant()) && MathF.Abs(m.GetDeterminant()) > float.Epsilon;

Try / catch

try
{
    image.Mutate(x => x.Transform(new ProjectiveTransformBuilder().AppendMatrix(m)));
}
catch (DegenerateTransformException ex)
{
    // substitute identity or last-known-good matrix
    throw;
}

Prevention

When it happens

Trigger: Creating a ProjectiveTransformProcessor or calling projective Mutate/Transform overloads with a matrix whose determinant (or relevant projective invariant) is zero, typically from a hand-built Matrix4x4 or from degenerate point correspondences.

Common situations: Hard-coded projective matrices with a zero row/column; concatenating transforms that cancel; building projective matrices from 4 coplanar source points via GaussianEliminationSolver (see the singular-matrix error at the same call depth).

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/42b0e4ccf24bae8d. Report an issue: GitHub.

Appendix: source

Thrown at src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs:26

/// <summary>
/// Defines a projective transformation applicable to an <see cref="Image"/>.
/// </summary>
public sealed class ProjectiveTransformProcessor : CloningImageProcessor
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ProjectiveTransformProcessor"/> class.
    /// </summary>
    /// <param name="matrix">The transform matrix.</param>
    /// <param name="sampler">The sampler to perform the transform operation.</param>
    /// <param name="targetDimensions">The target dimensions.</param>
    public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size targetDimensions)
    {
        Guard.NotNull(sampler, nameof(sampler));
        Guard.MustBeValueType(sampler);

        if (TransformUtilities.IsDegenerate(matrix))
        {
            throw new DegenerateTransformException("Matrix is degenerate. Check input values.");
        }

        this.Sampler = sampler;
        this.TransformMatrix = matrix;
        this.DestinationSize = targetDimensions;
    }

    /// <summary>
    /// Gets the sampler to perform interpolation of the transform operation.
    /// </summary>
    public IResampler Sampler { get; }

    /// <summary>
    /// Gets the matrix used to supply the projective transform.
    /// </summary>
    public Matrix4x4 TransformMatrix { get; }

    /// <summary>

View on GitHub (pinned to 59ce6af6fc)