bevyengine/bevy · critical

Color compression flag must be `COMPRESS_COLOR_FLOAT16` or `

Error message

Color compression flag must be `COMPRESS_COLOR_FLOAT16` or `COMPRESS_COLOR_UNORM8`

What it means

In the compressed-format selection match (crates/bevy_mesh/src/mesh.rs:1069-1086), the color arm is entered when the compression flags intersect COMPRESS_COLOR_RESERVED_BIT. The code then requires COMPRESS_COLOR_FLOAT16 or COMPRESS_COLOR_UNORM8 to be set and treats anything else as unreachable!. With the current bit layout (UNORM8 = 1 << shift, FLOAT16 = 2 << shift, RESERVED = both bits) any value intersecting the reserved bit necessarily contains one of the two, so this panic guards against bit-layout drift or flags built through from_bits_retain/serialization from an incompatible version.

Source

Thrown at crates/bevy_mesh/src/mesh.rs:1085

                Some(VertexFormat::Snorm16x2)
            }
            ATTRIBUTE_COLOR_ID
                if self
                    .attribute_compression
                    .intersects(MeshAttributeCompressionFlags::COMPRESS_COLOR_RESERVED_BIT) =>
            {
                if self
                    .attribute_compression
                    .contains(MeshAttributeCompressionFlags::COMPRESS_COLOR_FLOAT16)
                {
                    Some(VertexFormat::Float16x4)
                } else if self
                    .attribute_compression
                    .contains(MeshAttributeCompressionFlags::COMPRESS_COLOR_UNORM8)
                {
                    Some(VertexFormat::Unorm8x4)
                } else {
                    unreachable!("Color compression flag must be `COMPRESS_COLOR_FLOAT16` or `COMPRESS_COLOR_UNORM8`")
                }
            }
            ATTRIBUTE_JOINT_WEIGHT_ID
                if self
                    .attribute_compression
                    .contains(MeshAttributeCompressionFlags::COMPRESS_JOINT_WEIGHT) =>
            {
                Some(VertexFormat::Unorm16x4)
            }
            _ => None,
        }
    }

    /// Create compressed attribute values for the given attribute ID and attribute values. Return `None` if the compression flag is not set or the attribute values can't be compressed.
    ///
    /// Panics when compressing positions but `aabb` is `None`, or when compressing UVs but corresponding `uv_ranges` is `None`.
    fn create_compressed_attribute_values(
        &self,

View on GitHub (pinned to 396ca72708)

Solutions

  1. Build flags only from the named constants: use COMPRESS_COLOR_FLOAT16 or COMPRESS_COLOR_UNORM8 (or the with_color helper) instead of raw bit manipulation
  2. Never round-trip compression flag bits between different Bevy versions; re-derive them from settings
  3. If this fires with purely documented flag combinations, report it as a Bevy bug: the internal invariant is broken

Example fix

// before
let flags = MeshAttributeCompressionFlags::from_bits_retain(raw_bits); // may carry impossible color bits
let mesh = mesh.compressed_mesh(flags, false);

// after
let flags = MeshAttributeCompressionFlags::COMPRESS_POSITION
    | MeshAttributeCompressionFlags::COMPRESS_COLOR_UNORM8; // named constants only
let mesh = mesh.compressed_mesh(flags, false);
Defensive patterns

Strategy: validation

Validate before calling

fn color_compression_flags_valid(flags: MeshAttributeCompressionFlags) -> bool {
    let color_used = flags.intersects(
        MeshAttributeCompressionFlags::COMPRESS_COLOR_RESERVED_BIT,
    );
    !color_used
        || flags.contains(MeshAttributeCompressionFlags::COMPRESS_COLOR_FLOAT16)
            || flags.contains(MeshAttributeCompressionFlags::COMPRESS_COLOR_UNORM8)
}

assert!(color_compression_flags_valid(flags));

Prevention

When it happens

Trigger: Constructing MeshAttributeCompressionFlags with color bits in an impossible state: only possible via from_bits_retain/from_bits_transmute on unknown raw bits, or flags (de)serialized by a different Bevy version with a different color bit layout, followed by a call that resolves compressed vertex formats (e.g. compressed_mesh).

Common situations: Persisting MeshAttributeCompressionFlags across Bevy upgrades; hand-assembling bitflags from raw integers in tooling; unsafe transmute of flag values.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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