bevyengine/bevy · error · AutoExposureCompensationCurveError

curve could not be constructed from the given data

Error message

curve could not be constructed from the given data

What it means

`AutoExposureCompensationCurve::from_curve` (crates/bevy_post_process/src/auto_exposure/compensation_curve.rs:101) first converts the input curve to a cubic curve via `CubicGenerator::to_curve`; if that conversion fails, `AutoExposureCompensationCurveError::InvalidCurve` is returned. The curve maps log luminance (x) to exposure compensation (y) and is baked into a 256-entry LUT for the auto-exposure GPU pass.

Source

Thrown at crates/bevy_post_process/src/auto_exposure/compensation_curve.rs:46

    min_compensation: f32,
    /// The maximum exposure compensation value in the curve. (the y-axis)
    max_compensation: f32,
    /// The lookup table for the curve. Uploaded to the GPU as a 1D texture.
    /// Each value in the LUT is a `u8` representing a normalized exposure compensation value:
    /// * `0` maps to `min_compensation`
    /// * `255` maps to `max_compensation`
    ///
    /// The position in the LUT corresponds to the normalized log luminance value.
    /// * `0` maps to `min_log_lum`
    /// * `LUT_SIZE - 1` maps to `max_log_lum`
    lut: [u8; LUT_SIZE],
}

/// Various errors that can occur when constructing an [`AutoExposureCompensationCurve`].
#[derive(Error, Debug)]
pub enum AutoExposureCompensationCurveError {
    /// The curve couldn't be built in the first place.
    #[error("curve could not be constructed from the given data")]
    InvalidCurve,
    /// A discontinuity was found in the curve.
    #[error("discontinuity found between curve segments")]
    DiscontinuityFound,
    /// The curve is not monotonically increasing on the x-axis.
    #[error("curve is not monotonically increasing on the x-axis")]
    NotMonotonic,
}

impl Default for AutoExposureCompensationCurve {
    fn default() -> Self {
        Self {
            min_log_lum: 0.0,
            max_log_lum: 0.0,
            min_compensation: 0.0,
            max_compensation: 0.0,
            lut: [0; LUT_SIZE],
        }

View on GitHub (pinned to 396ca72708)

Solutions

  1. Ensure `from_points` receives at least two `Vec2` (log-lum, compensation) points
  2. Match the control-point count the chosen generator requires (e.g. 4 per segment for cubic Bezier)
  3. Log and fall back to the identity/zero curve when conversion fails, so one bad asset doesn't break scene load

Example fix

// before: malformed control points
let curve = AutoExposureCompensationCurve::from_curve(
    CubicBezier::new([vec2(0.0, 0.0)])).flatten()?; // too few points

// after: valid, sorted input
let curve = AutoExposureCompensationCurve::from_points([
    vec2(-4.0, -2.0),
    vec2(0.0, 0.0),
    vec2(4.0, 2.0),
])?;
Defensive patterns

Strategy: try-catch

Validate before calling

if points.len() < 2 {
    return Ok(AutoExposureCompensationCurve::default());
}

Try / catch

match AutoExposureCompensationCurve::from_points(points) {
    Err(AutoExposureCompensationCurveError::InvalidCurve) => {
        warn!("invalid compensation curve; using identity curve");
        AutoExposureCompensationCurve::default()
    }
    Err(e) => return Err(e.into()),
    Ok(curve) => curve,
}

Prevention

When it happens

Trigger: Passing a `CubicGenerator` (e.g. `CubicBezier`, or the spline built by `from_points`) whose control points cannot form valid cubic segments — wrong point count for the generator, degenerate/empty input. `from_points` with an empty or single-point list hits the same path.

Common situations: Building a compensation curve from artist/editor data at asset load; hot-reloading curve settings to zero points during development; porting curve data from another tool with mismatched control-point counts.

Related errors


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/b481ab32a8f045b7. Report an issue: GitHub.