rust-lang/rust · error
alt layout should always work
Error message
alt layout should always work
What it means
Internal layout invariant in rustc_abi's niche calculator (layout.rs:300). After a regular univariant layout with a niche is computed successfully, the compiler recomputes an end-biased (NicheBias::End) layout and expects it to also succeed via .expect("alt layout should always work"). The assumption: if the default field ordering yields a valid layout, the end-biased ordering must too. A panic here is a compiler bug (ICE), not a user error.
Solutions
- Treat this as an ICE: file a rustc issue with the minimized repro (the panic message is the anchor).
- Reduce the offending type: strip niched fields (Option, NonZero*, bool) and remove #[repr(...)] attributes until the panic disappears.
- Bisect with `cargo bisect-rustc` to find the regression, and try the same code on stable vs nightly.
- As a workaround, reorder fields or change the repr so the biased-niche recomputation path is not taken.
Defensive patterns
Strategy: fallback
Prevention
- This is a rustc ICE, not a recoverable error; do not try to catch it in user code.
- Minimize the offending type (remove niched fields and #[repr(...)]) and file a rustc issue.
- Use cargo bisect-rustc to find the regression and compare stable vs nightly.
- Pin to a known-good toolchain until the bug is fixed.
When it happens
Trigger: Lowering a multi-field struct/enum that has a niche (e.g. an Option/NonZero/bool field), head_space != 0, and tail_space > 0, so the biased-recomputation branch runs and univariant_biased returns Err.
Common situations: An ICE on nightly with unusual #[repr(...)] combinations or niche-bearing fields. This signals a bug in the layout algorithm, typically hit only by compiler developers or with exotic reprs.
Related errors
- alt layout should have a niche like the regular one
- expected pointee to have a layout
- expected `Session`
- missing QSelf for ::...
- must be at least one segment
AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10).
Data as JSON: /api/errors/49288306c628a8ab.
Report an issue: GitHub.
Appendix: source
Thrown at compiler/rustc_abi/src/layout.rs:300
// run and bias niches to the right and then check which one is closer to one of the
// struct's edges.
if let Ok(layout) = &layout {
// Don't try to calculate an end-biased layout for unsizable structs,
// otherwise we could end up with different layouts for
// Foo<Type> and Foo<dyn Trait> which would break unsizing.
if !matches!(kind, StructKind::MaybeUnsized) {
if let Some(niche) = layout.largest_niche {
let head_space = niche.offset.bytes();
let niche_len = niche.value.size(dl).bytes();
let tail_space = layout.size.bytes() - head_space - niche_len;
// This may end up doing redundant work if the niche is already in the last
// field (e.g. a trailing bool) and there is tail padding. But it's non-trivial
// to get the unpadded size so we try anyway.
if fields.len() > 1 && head_space != 0 && tail_space > 0 {
let alt_layout = self
.univariant_biased(fields, repr, kind, NicheBias::End)
.expect("alt layout should always work");
let alt_niche = alt_layout
.largest_niche
.expect("alt layout should have a niche like the regular one");
let alt_head_space = alt_niche.offset.bytes();
let alt_niche_len = alt_niche.value.size(dl).bytes();
let alt_tail_space =
alt_layout.size.bytes() - alt_head_space - alt_niche_len;
debug_assert_eq!(layout.size.bytes(), alt_layout.size.bytes());
let prefer_alt_layout =
alt_head_space > head_space && alt_head_space > tail_space;
debug!(
"sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\
layout: {}\n\
alt_layout: {}\n",
layout.size.bytes(),View on GitHub (pinned to 7088e4b63a)