bevyengine/bevy · warning · MismatchedUnitsError
cannot interpolate between two values of different units
Error message
cannot interpolate between two values of different units
What it means
TryStableInterpolate for bevy_ui::Val returns MismatchedUnitsError when the two endpoints use different variants — e.g. Val::Px(10.0) to Val::Percent(10.0) (crates/bevy_ui/src/geometry.rs:531-551). Interpolation within one variant is well-defined; across variants it is not, so the fallible API reports it. The design intent is that animated transitions detect the failure and snap to the target instead of blending.
Source
Thrown at crates/bevy_math/src/common_traits.rs:553
}
all_tuples_enumerated!(
#[doc(fake_variadic)]
impl_stable_interpolate_tuple,
1,
11,
T
);
impl<T: StableInterpolate, const LEN: usize> StableInterpolate for [T; LEN] {
fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
core::array::from_fn(|i| self[i].interpolate_stable(&other[i], t))
}
}
/// Error produced when the values to be interpolated are not in the same units.
#[derive(Clone, Debug, Error)]
#[error("cannot interpolate between two values of different units")]
pub struct MismatchedUnitsError;
/// A trait that indicates that a value _may_ be interpolable via [`StableInterpolate`]. An
/// interpolation may fail if the values have different units - for example, attempting to
/// interpolate between [`Val::Px`] and [`Val::Percent`] will fail,
/// even though they are the same Rust type.
///
/// Fallible interpolation can be used for animated transitions, which can be set up to fail
/// gracefully if the values cannot be interpolated. For example, a transition could smoothly
/// go from `Val::Px(10)` to `Val::Px(20)`, but if the user attempts to go from `Val::Px(10)` to
/// `Val::Percent(10)`, the animation player can detect the failure and simply snap to the new
/// value without interpolating.
///
/// An animation clip system can incorporate fallible interpolation to support a broad set of
/// sequenced parameter values. This can include numeric types, which always interpolate,
/// enum types, which may or may not interpolate depending on the units, and non-interpolable
/// types, which always jump immediately to the new value without interpolation. This means, for
/// example, that you can have an animation track whose value type is a boolean or a string.View on GitHub (pinned to 396ca72708)
Solutions
- Use the same Val variant for both endpoints of the transition.
- On Err(MismatchedUnitsError), snap to the target value — this is the documented graceful path.
- Convert one endpoint into the other's unit using the resolved layout size before animating.
Example fix
// before
let start = Val::Px(10.0);
let end = Val::Percent(50.0); // different variant -> MismatchedUnitsError
// after: snap on mismatch
let value = match start.try_interpolate_stable(&end, t) {
Ok(v) => v,
Err(MismatchedUnitsError) => end,
}; Defensive patterns
Strategy: fallback
Validate before calling
use bevy_math::{MismatchedUnitsError, TryStableInterpolate};
use bevy_ui::Val;
fn same_unit(a: &Val, b: &Val) -> bool {
matches!((a, b),
(Val::Px(_), Val::Px(_))
| (Val::Percent(_), Val::Percent(_))
| (Val::Vw(_), Val::Vw(_))
| (Val::Vh(_), Val::Vh(_))
| (Val::VMin(_), Val::VMin(_))
| (Val::VMax(_), Val::VMax(_))
| (Val::Auto, Val::Auto))
}
fn blend(a: Val, b: Val, t: f32) -> Val {
if same_unit(&a, &b) { a.try_interpolate_stable(&b, t).unwrap_or(b) } else { b }
} Try / catch
let value = match start.try_interpolate_stable(&end, t) {
Ok(v) => v,
Err(MismatchedUnitsError) => end, // documented graceful snap
}; Prevention
- Author transitions with matching Val variants on both ends.
- Treat interpolation failure as a snap, never as unwrap().
- When mixing units, resolve both to Px using layout size before animating.
When it happens
Trigger: Calling try_interpolate_stable (or an animation/tween system built on it) with endpoints of different Val variants: Px vs Percent, VMin vs Vw, etc.
Common situations: Style transitions authored with mixed units; UI defaults specified in Px while targets are in Percent; tween configs copied between UIs that use different unit systems.
Related errors
- cannot interpolate between two arrays of different lengths
- No focusable entity is currently set.
- No neighbor from {current_focus} in the {direction:?} direct
- Navigation explicitly blocked from {current_focus} in the {d
- No tab groups found
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/0bc5e6c00c4ffe55.
Report an issue: GitHub.