stride3d/stride · error · ArgumentException

Control points apply only to PrimitiveType.PatchList

Error message

Control points apply only to PrimitiveType.PatchList

What it means

This extension method returns a PrimitiveType configured with a control-point count, which is meaningful only for tessellation (PrimitiveType.PatchList). Calling it on any other primitive type throws ArgumentException naming the 'primitiveType' parameter. A subsequent validation bounds control points to 1..32.

Solutions

  1. Use PrimitiveType.PatchList.ControlPointCount(n) when configuring hull/tessellation stages.
  2. Only call ControlPointCount for tessellated pipelines; keep the plain primitive type otherwise.
  3. Validate the primitive type from configuration before invoking.

Example fix

// before
var type = PrimitiveType.TriangleList.ControlPointCount(3); // throws
// after
var type = PrimitiveType.PatchList.ControlPointCount(3);
Defensive patterns

Strategy: type-guard

Validate before calling

if (primitiveType != PrimitiveType.PatchList)
    throw new InvalidOperationException("ControlPointCount requires PatchList");
if (controlPoints is < 1 or > 32)
    throw new ArgumentOutOfRangeException(nameof(controlPoints));

Type guard

bool IsPatchList(PrimitiveType t) => t == PrimitiveType.PatchList;

Try / catch

try { type = primitiveType.ControlPointCount(n); }
catch (ArgumentException ex) { log.Error("control points need PatchList", ex); }

Prevention

When it happens

Trigger: Calling primitiveType.ControlPointCount(n) where primitiveType is not PatchList, e.g. TriangleList, LineStrip, or a default PrimitiveType value.

Common situations: Configuring tessellation stages with a generic primitive type; a settings/asset pipeline supplying a non-patch primitive type; misunderstanding that all PrimitiveType values accept control points.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/0c6f9fb7876b9797. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/PrimitiveTypeExtensions.cs:26

/// <summary>
///   Defines extensions and helpers for <see cref="PrimitiveType"/>.
/// </summary>
public static class PrimitiveTypeExtensions
{
    /// <summary>
    ///   Interpret the input vertex data type as a <strong>patch list</strong> for tesselation with a
    ///   specific number of <strong>control points</strong>.
    /// </summary>
    /// <param name="controlPoints">The number of control points. It must be a value in the range 1 to 32, inclusive.</param>
    /// <returns>
    ///   A <see cref="PrimitiveType"/> value that represents a patch list with the specified number of control points.
    /// </returns>
    /// <exception cref="ArgumentException">Control points apply only to <see cref="PrimitiveType.PatchList"/>.</exception>
    /// <exception cref="ArgumentOutOfRangeException"><paramref name="controlPoints"/> must be in the range 1 to 32, inclusive.</exception>"
    public static PrimitiveType ControlPointCount(this PrimitiveType primitiveType, int controlPoints)
    {
        if (primitiveType != PrimitiveType.PatchList)
            throw new ArgumentException($"Control points apply only to {nameof(PrimitiveType)}.{nameof(PrimitiveType.PatchList)}", nameof(primitiveType));

        const int MIN_CONTROL_POINTS = 1, MAX_CONTROL_POINTS = 32;

        if (controlPoints < MIN_CONTROL_POINTS || controlPoints > MAX_CONTROL_POINTS)
            throw new ArgumentOutOfRangeException(nameof(controlPoints), $"Value must be in between {MIN_CONTROL_POINTS} and {MAX_CONTROL_POINTS}");

        return PrimitiveType.PatchList + controlPoints - 1;
    }
}

View on GitHub (pinned to 96fad776d2)