{"record":{"id":"0d0316d90ef42759","repo":"bevyengine/bevy","slug":"invalid-knots-contains-descending-knot-pair","errorCode":null,"errorMessage":"Invalid knots: contains descending knot pair","messagePattern":"Invalid knots: contains descending knot pair","errorType":"exception","errorClass":"CubicNurbsError","httpStatus":null,"severity":"error","filePath":"crates/bevy_math/src/cubic_splines/mod.rs","lineNumber":537,"sourceCode":"            Ok(CubicCurve { segments })\n        }\n    }\n}\n\n/// Error during construction of [`CubicNurbs`]\n#[derive(Clone, Debug, Error)]\npub enum CubicNurbsError {\n    /// Provided the wrong number of knots.\n    #[error(\"Wrong number of knots: expected {expected}, provided {provided}\")]\n    KnotsNumberMismatch {\n        /// Expected number of knots\n        expected: usize,\n        /// Provided number of knots\n        provided: usize,\n    },\n    /// The provided knots had a descending knot pair. Subsequent knots must\n    /// either increase or stay the same.\n    #[error(\"Invalid knots: contains descending knot pair\")]\n    DescendingKnots,\n    /// The provided knots were all equal. Knots must contain at least one increasing pair.\n    #[error(\"Invalid knots: all knots are equal\")]\n    ConstantKnots,\n    /// Provided a different number of weights and control points.\n    #[error(\"Incorrect number of weights: expected {expected}, provided {provided}\")]\n    WeightsNumberMismatch {\n        /// Expected number of weights\n        expected: usize,\n        /// Provided number of weights\n        provided: usize,\n    },\n    /// The number of control points provided is less than 4.\n    #[error(\"Not enough control points, at least 4 are required, {provided} were provided\")]\n    NotEnoughControlPoints {\n        /// The number of control points provided\n        provided: usize,\n    },","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_math/src/cubic_splines/mod.rs#L519-L555","documentation":"Knot vectors must be a non-decreasing sequence: any adjacent pair with knots[i] > knots[i+1] returns DescendingKnots (cubic_splines/mod.rs:667-669). Repeated values are allowed (knot multiplicity, useful for sharp corners); only decreases are invalid.","triggerScenarios":"Passing an unsorted or hand-edited knot vector; importing parameterizations that run descending; sign mistakes or transposed values in long vectors.","commonSituations":"Manually authored knot arrays in level/tooling data; knots exported from DCC tools with reversed parameters; copy-paste errors in 8+ element vectors.","solutions":["Sort the knot vector ascending before passing it (stable repeats preserved).","Validate with knots.windows(2).all(|w| w[0] <= w[1]) at load time.","Pass None for knots if custom parameterization is not required."],"exampleFix":"// before\nlet knots = [5.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0, 0.0]; // descending pairs -> error\n\n// after\nlet mut knots = knots;\nknots.sort_by(|a, b| a.partial_cmp(b).unwrap());\nlet nurbs = CubicNurbs::new(pts, None, Some(knots))?;","handlingStrategy":"validation","validationCode":"fn knots_nondecreasing(knots: &[f32]) -> bool {\n    knots.windows(2).all(|w| w[0] <= w[1])\n}\n\nlet knots = {\n    let mut k = knots.to_vec();\n    k.sort_by(|a, b| a.partial_cmp(b).unwrap());\n    k\n};\nassert!(knots_nondecreasing(&knots));","typeGuard":null,"tryCatchPattern":"match CubicNurbs::new(points, None, Some(knots)) {\n    Err(CubicNurbsError::DescendingKnots) => { /* sort knots ascending and retry */ }\n    Ok(n) => { /* use n */ }\n    Err(e) => warn!(\"{e}\"),\n}","preventionTips":["Sort imported knot vectors non-decreasing at load time.","Remember repeats are allowed (multiplicity), only decreases are invalid.","Add a windows(2) monotonicity check to asset validation."],"tags":["bevy","math","spline","nurbs","knots","sorting"],"backgroundTag":"non-monotonic-knots","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}