stride3d/stride · error · InvalidOperationException

Invalid state when computing tetrahedron

Error message

Invalid state when computing tetrahedron

What it means

BowyerWatsonTetrahedralization computes a tetrahedralization for light probe placement. While checking whether a point is inside a tetrahedron's circumsphere, it builds a plane for one of the four faces using a switch over face indices; if the face index is outside 0-3 the internal face-index table is corrupt, so the library throws InvalidOperationException rather than produce a wrong tetrahedralization.

Solutions

  1. Check for duplicate or exactly collinear light probe point coordinates in the input set and remove/offset them
  2. Verify no custom modifications to BowyerWatsonTetrahedralization broke the face-index table (indices 0-3)
  3. Capture the input point set and report a bug to Stride with a minimal reproducible probe layout
  4. Update Stride to the latest version in case the tetrahedralization bug was fixed upstream

Example fix

// before: duplicate probe positions collapse face bookkeeping
var points = new[] { p0, p1, p1, p2 };
// after: deduplicate points before tetrahedralization
var points = probePositions.Distinct().ToArray();
Defensive patterns

Strategy: try-catch

Validate before calling

// deduplicate and sanity-check probe points before tetrahedralization
var distinct = probePositions.Distinct().ToList();
if (distinct.Count < 4) throw new ArgumentException("Need at least 4 distinct probe points");

Type guard

bool IsValidProbeSet(IReadOnlyList<Vector3> pts) =>
    pts.Distinct().Count() == pts.Count && pts.Count >= 4;

Try / catch

try { var tetra = new BowyerWatsonTetrahedralization(points); ... }
catch (InvalidOperationException ex)
{
    logger.LogError(ex, "Tetrahedralization failed; check probe point layout");
    // fall back to grid-based probe placement
}

Prevention

When it happens

Trigger: Internal state corruption in the tetrahedralization: the infinityIndices / face-index mapping yields a value outside 0-3 when computing the bounding planes of the super-tetrahedron during InSphere checks. Only reachable via BowyerWatsonTetrahedralization with degenerate or duplicate probe points that corrupt the face bookkeeping.

Common situations: Custom light probe setups with coincident or collinear probe points, or a modified/patched copy of the algorithm breaking the face-index invariants; not normally reachable through supported public APIs.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Rendering/Rendering/LightProbes/BowyerWatsonTetrahedralization.cs:732

                    Vector3 normal;
                    switch (unused)
                    {
                        case 0:
                            normal = new Vector3(1.0f, 1.0f, 1.0f);
                            normal.Normalize();
                            break;
                        case 1:
                            normal = -Vector3.UnitZ;
                            break;
                        case 2:
                            normal = -Vector3.UnitY;
                            break;
                        case 3:
                            normal = -Vector3.UnitX;
                            break;
                        default:
                            throw new InvalidOperationException("Invalid state when computing tetrahedron");
                    }

                    var plane = new Plane(points[infinityIndices[0]], normal);
                    var result = Predicates.insphere(ref points[tetrahedronPointer->Vertices[0]], ref points[tetrahedronPointer->Vertices[1]], ref points[tetrahedronPointer->Vertices[2]], ref points[tetrahedronPointer->Vertices[3]], ref p);
                    return CollisionHelper.DistancePlanePoint(ref plane, ref p) > 0.0f;
                }
                else if (infinityCount == 2)
                {
                    // Build a plane that contains both points not at infinity, and that is also parallel to the line formed by the two points at "infinity"
                    var infinitePerpendicularLine = points[infinityIndices[3]] - points[infinityIndices[2]];
                    var plane = new Plane(points[infinityIndices[0]], points[infinityIndices[1]], points[infinityIndices[0]] + infinitePerpendicularLine);
                    var result = Predicates.insphere(ref points[tetrahedronPointer->Vertices[0]], ref points[tetrahedronPointer->Vertices[1]], ref points[tetrahedronPointer->Vertices[2]], ref points[tetrahedronPointer->Vertices[3]], ref p);
                    return CollisionHelper.DistancePlanePoint(ref plane, ref p) > 0.0f;
                }
                else if (infinityCount == 1)
                {
                    // 1 from super tetrahedra out of 4
                    // Find which one is used

View on GitHub (pinned to 96fad776d2)