{"record":{"id":"f33c0c0708b077cf","repo":"bevyengine/bevy","slug":"curve-is-not-monotonically-increasing-on-the-x-axi","errorCode":null,"errorMessage":"curve is not monotonically increasing on the x-axis","messagePattern":"curve is not monotonically increasing on the x-axis","errorType":"exception","errorClass":"AutoExposureCompensationCurveError","httpStatus":null,"severity":"error","filePath":"crates/bevy_post_process/src/auto_exposure/compensation_curve.rs","lineNumber":52,"sourceCode":"    /// * `255` maps to `max_compensation`\n    ///\n    /// The position in the LUT corresponds to the normalized log luminance value.\n    /// * `0` maps to `min_log_lum`\n    /// * `LUT_SIZE - 1` maps to `max_log_lum`\n    lut: [u8; LUT_SIZE],\n}\n\n/// Various errors that can occur when constructing an [`AutoExposureCompensationCurve`].\n#[derive(Error, Debug)]\npub enum AutoExposureCompensationCurveError {\n    /// The curve couldn't be built in the first place.\n    #[error(\"curve could not be constructed from the given data\")]\n    InvalidCurve,\n    /// A discontinuity was found in the curve.\n    #[error(\"discontinuity found between curve segments\")]\n    DiscontinuityFound,\n    /// The curve is not monotonically increasing on the x-axis.\n    #[error(\"curve is not monotonically increasing on the x-axis\")]\n    NotMonotonic,\n}\n\nimpl Default for AutoExposureCompensationCurve {\n    fn default() -> Self {\n        Self {\n            min_log_lum: 0.0,\n            max_log_lum: 0.0,\n            min_compensation: 0.0,\n            max_compensation: 0.0,\n            lut: [0; LUT_SIZE],\n        }\n    }\n}\n\nimpl AutoExposureCompensationCurve {\n    const SAMPLES_PER_SEGMENT: usize = 64;\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_post_process/src/auto_exposure/compensation_curve.rs#L34-L70","documentation":"While sampling the cubic curve into the compensation LUT, `from_curve` requires the log-luminance axis to be non-decreasing: any sample with `current.x < previous.x` (crates/bevy_post_process/src/auto_exposure/compensation_curve.rs:127) returns `AutoExposureCompensationCurveError::NotMonotonic`. The LUT maps log luminance linearly onto its 256 entries, so a curve that doubles back on x cannot be encoded.","triggerScenarios":"`from_points` with x values out of order, duplicated x values producing local decreases after spline interpolation, or control points that make the cubic overshoot backwards on x even when the raw points are sorted.","commonSituations":"Artist data pasted in arbitrary order; duplicated rows in a CSV of curve points; spline interpolation overshooting between close x values.","solutions":["Sort points by x before calling `from_points` and drop exact duplicates","If cubic interpolation still overshoots backwards between near-equal x values, use denser/more evenly spaced x samples","Validate monotonicity of the built curve before registering the asset"],"exampleFix":"// before: unsorted x -> NotMonotonic\nlet pts = [vec2(2.0, 0.5), vec2(-4.0, -2.0), vec2(0.0, 0.0)];\n\n// after: sort by x, remove duplicates\nlet mut pts: Vec<Vec2> = raw_points.to_vec();\npts.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap());\npts.dedup_by(|a, b| a.x == b.x);\nlet curve = AutoExposureCompensationCurve::from_points(pts)?;","handlingStrategy":"validation","validationCode":"let mut pts: Vec<Vec2> = raw.to_vec();\npts.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap());\npts.dedup_by(|a, b| a.x == b.x);\nlet curve = AutoExposureCompensationCurve::from_points(pts)?;","typeGuard":null,"tryCatchPattern":"match AutoExposureCompensationCurve::from_points(pts) {\n    Err(AutoExposureCompensationCurveError::NotMonotonic) => {\n        warn!(\"compensation curve x-axis not monotonic; sorting input\");\n        pts.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap());\n        AutoExposureCompensationCurve::from_points(pts)?\n    }\n    other => other?,\n}","preventionTips":["Normalize all curve data through a sort+dedupe step before conversion","Avoid near-equal x values that make cubic interpolation overshoot backwards","Reject non-finite x/y values at import time"],"tags":["bevy","auto-exposure","curve","monotonicity","post-processing"],"backgroundTag":"curve-construction-failed","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}