{"record":{"id":"2aed5d00f19d383e","repo":"stride3d/stride","slug":"inconsistency-two-tetrahedra-don-t-agree-on-their-neighbour","errorCode":null,"errorMessage":"Inconsistency: two tetrahedra don't agree on their neighbour information (they should both reference each other)","messagePattern":"Inconsistency: two tetrahedra don't agree on their neighbour information \\(they should both reference each other\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Rendering/Rendering/LightProbes/BowyerWatsonTetrahedralization.cs","lineNumber":484,"sourceCode":"                        // If edge is not shared by any other bad tetrahedra, it means it's a boundary of our polygonal hole\n                        var neighbourTetrahedronIndex = tetrahedron->Neighbours[i];\n                        if (badTetrahedra.BinarySearch(neighbourTetrahedronIndex) < 0)\n                        {\n                            var neighbourTetrahedronSelfIndex = -1;\n                            if (neighbourTetrahedronIndex != -1)\n                            {\n                                // Find the neighbour index of current tetrahedra in neighbourTetrahedra\n                                var neighbourTetrahedron = &tetrahedra[neighbourTetrahedronIndex];\n                                for (int j = 0; j < 4; ++j)\n                                {\n                                    if (neighbourTetrahedron->Neighbours[j] == tetrahedronIndex)\n                                    {\n                                        neighbourTetrahedronSelfIndex = j;\n                                        break;\n                                    }\n                                }\n                                if (neighbourTetrahedronSelfIndex == -1)\n                                    throw new InvalidOperationException(\"Inconsistency: two tetrahedra don't agree on their neighbour information (they should both reference each other)\");\n                            }\n\n                            // Store edges information (to easily reconstruct neighbour after)\n                            var vertex0 = tetrahedron->Vertices[(i + 1) % 4];\n                            var vertex1 = tetrahedron->Vertices[(i + 2) % 4];\n                            var vertex2 = tetrahedron->Vertices[(i + 3) % 4];\n\n                            // If new vertex is at an odd position, it means that newly constructed tetrahedron would have a negative order, let's swap 2 vertices\n                            //if (!IsTetrahedraPositiveOrder(ref vertex, ref vertices[vertex0], ref vertices[vertex1], ref vertices[vertex2]))\n                            if (i % 2 == 1)\n                            {\n                                var vertexTemp = vertex1;\n                                vertex1 = vertex2;\n                                vertex2 = vertexTemp;\n                            }\n\n                            if (!IsTetrahedronPositiveOrder(ref vertex, ref vertices[vertex0], ref vertices[vertex1], ref vertices[vertex2]))\n                                throw new InvalidOperationException();","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Rendering/Rendering/LightProbes/BowyerWatsonTetrahedralization.cs#L466-L502","documentation":"CheckConnectivity (invoked from the BowyerWatsonTetrahedralization constructor) validates that neighbouring tetrahedra reference each other symmetrically. When a tetrahedron lists a neighbour, but that neighbour's own Neighbours array has no slot pointing back, the invariant is broken and InvalidOperationException is thrown.","triggerScenarios":"A bug condition in AddVertex's cavity re-triangulation where an edge's recorded neighbour index doesn't match any face of the neighbour tetrahedron, detected during the constructor's connectivity pass.","commonSituations":"Practically only hit during light-probe baking on tetrahedralizations with many probes where numeric edge bookkeeping can diverge; indicates an engine bug rather than user error.","solutions":["Verify probe positions don't contain duplicates or near-degenerate configurations that stress the algorithm","Reduce/simplify the probe layout and retry baking","Report to Stride as an internal tetrahedralization bug if reproducible with a simple probe group"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (probes.Select(p => p).Distinct().Count() != probes.Count)\n    throw new ArgumentException(\"Duplicate probes can break tetrahedralization\");","typeGuard":null,"tryCatchPattern":"try { var t = new BowyerWatsonTetrahedralization(vertices); }\ncatch (InvalidOperationException e) { logger.Error(e, \"Tetrahedralization connectivity failure\"); /* fall back to brute-force lookup */ }","preventionTips":["Report persistent occurrences as engine bugs","Use well-spaced, non-degenerate probe layouts","Keep probe groups modest in size when baking"],"tags":["csharp","geometry","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}