bevyengine/bevy · error · GridPlacementError

Spans cannot be zero length

Error message

Spans cannot be zero length

What it means

GridPlacementError::InvalidZeroSpan is the thiserror variant produced by try_into_grid_span when a u16 span of 0 fails NonZero::new — 'Spans cannot be zero length'. The public constructors .expect() it (surfacing as the 'Invalid span value of 0.' panics), and the Display text appears when the error is propagated or formatted by fallible user code built on the enum.

Source

Thrown at crates/bevy_ui/src/ui_node.rs:2252

fn try_into_grid_index(index: i16) -> Result<Option<NonZero<i16>>, GridPlacementError> {
    Ok(Some(
        NonZero::<i16>::new(index).ok_or(GridPlacementError::InvalidZeroIndex)?,
    ))
}

/// Convert a `u16` to `NonZero<u16>`, fails on `0` and returns the `InvalidZeroSpan` error.
fn try_into_grid_span(span: u16) -> Result<Option<NonZero<u16>>, GridPlacementError> {
    Ok(Some(
        NonZero::<u16>::new(span).ok_or(GridPlacementError::InvalidZeroSpan)?,
    ))
}

/// Errors that occur when setting constraints for a `GridPlacement`
#[derive(Debug, Eq, PartialEq, Clone, Copy, Error)]
pub enum GridPlacementError {
    #[error("Zero is not a valid grid position")]
    InvalidZeroIndex,
    #[error("Spans cannot be zero length")]
    InvalidZeroSpan,
}

/// The background color of the node
///
/// This serves as the "fill" color.
#[derive(Component, Copy, Clone, Debug, Deref, DerefMut, PartialEq, Reflect)]
#[reflect(Component, Default, Debug, PartialEq, Clone)]
#[cfg_attr(
    feature = "serialize",
    derive(serde::Serialize, serde::Deserialize),
    reflect(Serialize, Deserialize)
)]
pub struct BackgroundColor(pub Color);

impl BackgroundColor {
    /// Background color is transparent by default.
    pub const DEFAULT: Self = Self(Color::NONE);

View on GitHub (pinned to 227d3a6c66)

Solutions

  1. Guarantee spans are >= 1 at the call site; one track is the minimum occupancy.
  2. Map InvalidZeroSpan in fallible code to a default span of 1 (or reject the record with a precise message).
  3. Skip creating the node when a computed span legitimately equals 0 rather than remapping silently.
  4. Unit-test data sources (configs, save files) for zero spans before they reach GridPlacement.

Example fix

// before
fn item(span: u16) -> Result<GridPlacement, GridPlacementError> {
    Ok(GridPlacement::span(span)) // panics on span == 0
}

// after
fn item(span: u16) -> Result<GridPlacement, GridPlacementError> {
    if span == 0 { return Err(GridPlacementError::InvalidZeroSpan); }
    Ok(GridPlacement::span(span))
}
Defensive patterns

Strategy: validation

Validate before calling

use std::num::NonZero;

fn checked_span(span: u16) -> Result<NonZero<u16>, GridPlacementError> {
    NonZero::new(span).ok_or(GridPlacementError::InvalidZeroSpan)
}

Type guard

fn is_valid_grid_span(span: u16) -> bool { span != 0 }

Try / catch

match checked_span(span) {
    Ok(span) => Ok(GridPlacement::span(span.get())),
    Err(e @ GridPlacementError::InvalidZeroSpan) => {
        warn!("{e}");
        Ok(GridPlacement::auto()) // span defaults to 1
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Passing span == 0 to GridPlacement::span/start_span/end_span or set_span (converted to a panic); handling or logging a GridPlacementError::InvalidZeroSpan returned from a fallible placement-validation layer.

Common situations: Defensive placement builders that return Result and need to distinguish bad spans from bad lines; data-validation pipelines reporting why a serialized layout was rejected; shared layout libraries reused across Bevy versions.

Related errors


AI-assisted analysis of bevyengine/bevy@227d3a6c66 (2026-08-20). Data as JSON: /api/errors/048c959ddea2b0c2. Report an issue: GitHub.