SixLabors/ImageSharp · error · DegenerateTransformException

Matrix is degenerate. Check input values.

Error message

Matrix is degenerate. Check input values.

What it means

ProjectiveTransformBuilder.CheckDegenerate runs before matrices are combined (PrependMatrix, AppendMatrix) and again in BuildMatrix, so any intermediate or final composition of appended transforms that becomes degenerate is rejected early with DegenerateTransformException. This prevents silently producing a transform that maps everything to a line/point.

Solutions

  1. Validate each Matrix4x4 with Matrix4x4.GetDeterminant() != 0 before Append/Prepend
  2. Ensure each appended factory produces a valid transform for the actual runtime size (factories receive Size at build time)
  3. Catch DegenerateTransformException around BuildMatrix since composed matrices can degenerate even if each part is fine
  4. Reduce the chain to the minimal set of transforms and add them back one at a time to find the offender

Example fix

// before
builder.AppendMatrix(brokenMatrix); // determinant == 0
// after
if (Math.Abs(brokenMatrix.GetDeterminant()) < float.Epsilon)
{
    throw new InvalidOperationException("Refusing to append degenerate matrix.");
}
builder.AppendMatrix(brokenMatrix);
Defensive patterns

Strategy: validation

Validate before calling

static bool IsNonDegenerate(Matrix4x4 m) => MathF.Abs(m.GetDeterminant()) > 1e-6f;
foreach (var factory in transformFactories)
{
    if (!IsNonDegenerate(factory(size))) throw new InvalidOperationException("Degenerate matrix in builder chain.");
}

Type guard

static bool IsAppendable(Matrix4x4 m) => MathF.Abs(m.GetDeterminant()) > float.Epsilon;

Try / catch

try
{
    var matrix = builder.BuildMatrix(destinationSize);
}
catch (DegenerateTransformException ex)
{
    // inspect builder chain; fall back to affine or identity
    throw;
}

Prevention

When it happens

Trigger: Calling AppendMatrix/PrependMatrix with a degenerate Matrix4x4, or appending factories whose composition (evaluated in BuildMatrix) is degenerate — e.g. appending a scale-0 transform or one that nullifies a prior one.

Common situations: Chaining several transform factories where one produces a zero scale; building transforms from user-supplied corner points that are collinear; refactoring builder code and losing a guard on an individual matrix before appending.

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/9ba431744f29ea30. Report an issue: GitHub.

Appendix: source

Thrown at src/ImageSharp/Processing/ProjectiveTransformBuilder.cs:414

    /// <returns>The <see cref="Size"/>.</returns>
    internal static SizeF GetTransformedSize(Rectangle sourceRectangle, Matrix4x4 matrix)
        => TransformUtilities.GetRawTransformedSize(matrix, sourceRectangle.Size);

    /// <summary>
    /// Clears all accumulated transform matrices, resetting the builder to its initial state.
    /// </summary>
    /// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns>
    public ProjectiveTransformBuilder Clear()
    {
        this.transformMatrixFactories.Clear();
        return this;
    }

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

    private ProjectiveTransformBuilder Prepend(Func<Size, Matrix4x4> transformFactory)
    {
        this.transformMatrixFactories.Insert(0, transformFactory);
        return this;
    }

    private ProjectiveTransformBuilder Append(Func<Size, Matrix4x4> transformFactory)
    {
        this.transformMatrixFactories.Add(transformFactory);
        return this;
    }
}

View on GitHub (pinned to 59ce6af6fc)