{"record":{"id":"5799f2c240835d92","repo":"bevyengine/bevy","slug":"color-compression-flag-must-be-compress-color-flo","errorCode":null,"errorMessage":"Color compression flag must be `COMPRESS_COLOR_FLOAT16` or `COMPRESS_COLOR_UNORM8`","messagePattern":"Color compression flag must be `COMPRESS_COLOR_FLOAT16` or `COMPRESS_COLOR_UNORM8`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/bevy_mesh/src/mesh.rs","lineNumber":1085,"sourceCode":"                Some(VertexFormat::Snorm16x2)\n            }\n            ATTRIBUTE_COLOR_ID\n                if self\n                    .attribute_compression\n                    .intersects(MeshAttributeCompressionFlags::COMPRESS_COLOR_RESERVED_BIT) =>\n            {\n                if self\n                    .attribute_compression\n                    .contains(MeshAttributeCompressionFlags::COMPRESS_COLOR_FLOAT16)\n                {\n                    Some(VertexFormat::Float16x4)\n                } else if self\n                    .attribute_compression\n                    .contains(MeshAttributeCompressionFlags::COMPRESS_COLOR_UNORM8)\n                {\n                    Some(VertexFormat::Unorm8x4)\n                } else {\n                    unreachable!(\"Color compression flag must be `COMPRESS_COLOR_FLOAT16` or `COMPRESS_COLOR_UNORM8`\")\n                }\n            }\n            ATTRIBUTE_JOINT_WEIGHT_ID\n                if self\n                    .attribute_compression\n                    .contains(MeshAttributeCompressionFlags::COMPRESS_JOINT_WEIGHT) =>\n            {\n                Some(VertexFormat::Unorm16x4)\n            }\n            _ => None,\n        }\n    }\n\n    /// 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.\n    ///\n    /// Panics when compressing positions but `aabb` is `None`, or when compressing UVs but corresponding `uv_ranges` is `None`.\n    fn create_compressed_attribute_values(\n        &self,","sourceCodeStart":1067,"sourceCodeEnd":1103,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_mesh/src/mesh.rs#L1067-L1103","documentation":"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.","triggerScenarios":"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).","commonSituations":"Persisting MeshAttributeCompressionFlags across Bevy upgrades; hand-assembling bitflags from raw integers in tooling; unsafe transmute of flag values.","solutions":["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","Never round-trip compression flag bits between different Bevy versions; re-derive them from settings","If this fires with purely documented flag combinations, report it as a Bevy bug: the internal invariant is broken"],"exampleFix":"// before\nlet flags = MeshAttributeCompressionFlags::from_bits_retain(raw_bits); // may carry impossible color bits\nlet mesh = mesh.compressed_mesh(flags, false);\n\n// after\nlet flags = MeshAttributeCompressionFlags::COMPRESS_POSITION\n    | MeshAttributeCompressionFlags::COMPRESS_COLOR_UNORM8; // named constants only\nlet mesh = mesh.compressed_mesh(flags, false);","handlingStrategy":"validation","validationCode":"fn color_compression_flags_valid(flags: MeshAttributeCompressionFlags) -> bool {\n    let color_used = flags.intersects(\n        MeshAttributeCompressionFlags::COMPRESS_COLOR_RESERVED_BIT,\n    );\n    !color_used\n        || flags.contains(MeshAttributeCompressionFlags::COMPRESS_COLOR_FLOAT16)\n            || flags.contains(MeshAttributeCompressionFlags::COMPRESS_COLOR_UNORM8)\n}\n\nassert!(color_compression_flags_valid(flags));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build MeshAttributeCompressionFlags only from named constants or with_color","Never persist raw flag bits across Bevy upgrades; re-derive them from settings","Avoid from_bits_retain for compression flags; validate unknown bits and reject them"],"tags":["bevy","bevy-mesh","rust","mesh","compression","bitflags","unreachable","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}