zed-industries/zed · warning

button layout string {:?} contains no valid buttons (unrecog

Error message

button layout string {:?} contains no valid buttons (unrecognized: {})

What it means

WindowButtonLayout::parse reads a GNOME-style 'button-layout' string ('left:right', e.g. 'close,minimize:maximize'). Only the tokens 'minimize', 'maximize' and 'close' are recognized; unknown tokens are collected, and the parse fails only when every token on both sides was unrecognized — i.e. the string yields no usable buttons at all. Partial garbage is tolerated.

Source

Thrown at crates/gpui/src/platform.rs:727

                    }
                }
            }
            result
        }

        let (left_str, right_str) = layout_string.split_once(':').unwrap_or(("", layout_string));
        let mut unrecognized = Vec::new();
        let mut seen_buttons = [false; MAX_BUTTONS_PER_SIDE];
        let layout = Self {
            left: parse_side(left_str, &mut seen_buttons, &mut unrecognized),
            right: parse_side(right_str, &mut seen_buttons, &mut unrecognized),
        };

        if !unrecognized.is_empty()
            && layout.left.iter().all(Option::is_none)
            && layout.right.iter().all(Option::is_none)
        {
            bail!(
                "button layout string {:?} contains no valid buttons (unrecognized: {})",
                layout_string,
                unrecognized.join(", ")
            );
        }

        Ok(layout)
    }

    /// Formats the layout back into a GNOME-style `button-layout` string.
    #[cfg(test)]
    pub fn format(&self) -> String {
        fn format_side(buttons: &[Option<WindowButton>; MAX_BUTTONS_PER_SIDE]) -> String {
            buttons
                .iter()
                .flatten()
                .map(|button| match button {
                    WindowButton::Minimize => "minimize",

View on GitHub (pinned to 9d272b0363)

Solutions

  1. Use the recognized lowercase names: minimize, maximize, close (e.g. 'close,minimize:maximize')
  2. Fix casing and separators — tokens are lowercase and comma-separated per side
  3. If the value comes from the desktop environment, normalize it before passing in, or fall back to WindowButtonLayout::linux_default()

Example fix

// before
let layout = WindowButtonLayout::parse("Close,Minimize")?; // capitalized -> all unrecognized -> bail

// after
let layout = WindowButtonLayout::parse("close,minimize:maximize")?;
Defensive patterns

Strategy: validation

Validate before calling

const KNOWN_BUTTONS: &[&str] = &["minimize", "maximize", "close"];
fn plausible_layout(s: &str) -> bool {
    s.split(':')
        .flat_map(|side| side.split(','))
        .any(|token| KNOWN_BUTTONS.contains(&token.trim()))
}

Try / catch

let layout = WindowButtonLayout::parse(raw).unwrap_or_else(|err| {
    log::warn!("unusable button-layout '{raw}': {err}; using default");
    WindowButtonLayout::linux_default()
});

Prevention

When it happens

Trigger: Passing a string whose every comma-separated token is unknown: 'foo:bar', ':qux', or a whole string like 'Close,Minimize' where capitalized tokens do not match the lowercase names. With no ':' present, the entire string is parsed as the right side.

Common situations: Reading gtk-decoration-layout or gsettings values containing unexpected or locale-specific tokens; hand-rolled config using invented button names; casing mismatches when transcribing GNOME settings.

Related errors


AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-08-20). Data as JSON: /api/errors/cc3930d5948829ff. Report an issue: GitHub.