LGUG2Z/komorebi · error

custom layouts must be json or yaml files

Error message

custom layouts must be json or yaml files

What it means

CustomLayout::from_path loads a user-defined layout and only accepts .json, .yaml, or .yml extensions. Any other extension (or none) reaches the bail! arm with this message, aborting with an eyre error.

Source

Thrown at komorebi-layouts/src/custom_layout.rs:42

}

impl DerefMut for CustomLayout {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl CustomLayout {
    pub fn from_path<P: AsRef<Path>>(path: P) -> eyre::Result<Self> {
        let path = path.as_ref();
        let layout: Self = match path.extension() {
            Some(extension) if extension == "yaml" || extension == "yml" => {
                serde_json::from_reader(BufReader::new(File::open(path)?))?
            }
            Some(extension) if extension == "json" => {
                serde_json::from_reader(BufReader::new(File::open(path)?))?
            }
            _ => bail!("custom layouts must be json or yaml files"),
        };

        if !layout.is_valid() {
            bail!("the layout file provided was invalid");
        }

        Ok(layout)
    }

    #[must_use]
    pub fn column_with_idx(&self, idx: usize) -> (usize, Option<&Column>) {
        let column_idx = self.column_for_container_idx(idx);
        let column = self.get(column_idx);
        (column_idx, column)
    }

    #[must_use]
    pub fn primary_idx(&self) -> Option<usize> {

View on GitHub (pinned to e0709f02bf)

Solutions

  1. Rename the layout file to end with .json (or .yaml/.yml).
  2. Confirm the path passed via --layout or custom_layouts config points at the correct file.
  3. If the layout is in another format, convert it to JSON first.

Example fix

// before
komorebic --layout ultrawide.txt
// after
komorebic --layout ultrawide.json
Defensive patterns

Strategy: validation

Validate before calling

let ext = std::path::Path::new(layout_path)
    .extension()
    .map(|e| e.to_string_lossy().to_lowercase());
assert!(matches!(ext.as_deref(), Some("json") | Some("yaml") | Some("yml")), "layout must be json or yaml");

Type guard

fn is_supported_layout(path: &std::path::Path) -> bool {
    path.extension().map(|e| {
        matches!(e.to_string_lossy().to_lowercase().as_str(), "json" | "yaml" | "yml")
    }).unwrap_or(false)
}

Try / catch

match CustomLayout::from_path(&path) {
    Ok(l) => l,
    Err(e) => eprintln!("layout load failed: {e}; use .json/.yaml/.yml"),
}

Prevention

When it happens

Trigger: Calling CustomLayout::from_path with a file whose extension is not json/yaml/yml, e.g. my_layout.txt, layout, or layout.json5. Referenced via komorebic --layout or static/dynamic layout config.

Common situations: Saving a downloaded layout without its extension; using .yason/.toml; text editor appending .txt; pointing --layout at documentation instead of the actual layout file.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of LGUG2Z/komorebi@e0709f02bf (2026-09-06). Data as JSON: /api/errors/1acc01a04f27b90d. Report an issue: GitHub.