jdx/mise · error

brew-cask: invalid font target '{}'

Error message

brew-cask: invalid font target '{}'

What it means

The final font install path is font_dir().join(name), where the name is derived from the cask's font stanza. font_target_path requires that name to be a non-empty, purely relative filename: not absolute and free of '..' components, so a font can never be written outside the user's font directory.

Source

Thrown at src/system/packages/brew/cask.rs:2778

            .filter(|entry| entry.file_type().is_ok_and(|ft| ft.is_dir()))
            .any(|entry| relative.is_some_and(|path| entry.path().join(path).is_file()));
        if has_staged_copy {
            file::remove_file(target)?;
        }
    }
    Ok(())
}

fn font_target_path(font: &FontArtifact) -> Result<PathBuf> {
    let name = font_filename(font)?;
    let name_path = Path::new(&name);
    if name_path.is_absolute()
        || name_path
            .components()
            .any(|component| matches!(component, Component::ParentDir))
        || name_path.components().next().is_none()
    {
        bail!("brew-cask: invalid font target '{}'", name);
    }
    Ok(font_dir().join(name_path))
}

fn font_dir() -> PathBuf {
    if cfg!(target_os = "linux") {
        crate::env::XDG_DATA_HOME.join("fonts")
    } else {
        crate::dirs::HOME.join("Library").join("Fonts")
    }
}

#[cfg(test)]
fn execute_flight_steps(
    cask: &Cask,
    steps: &[FlightStep],
    staged_path: &Path,
    appdir: &Path,

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Fix the font stanza to a plain file name like "MyFont-Regular.otf"
  2. Strip directory components from the name before it reaches font handling
  3. Report malformed stanzas in third-party taps upstream

Example fix

# before
font: "/Library/Fonts/MyFont.ttf"

# after
font: "MyFont.ttf"
Defensive patterns

Strategy: validation

Validate before calling

use std::path::{Path, Component};

fn is_plain_filename(name: &str) -> bool {
    let p = Path::new(name);
    !p.is_absolute()
        && p.components().next().is_some()
        && !p.components().any(|c| matches!(c, Component::ParentDir))
}

Type guard

fn is_plain_font_filename(name: &str) -> bool {
    let p = std::path::Path::new(name);
    !p.is_absolute() && p.components().next().is_some()
        && !p.components().any(|c| matches!(c, std::path::Component::ParentDir))
}

Prevention

When it happens

Trigger: A font filename that starts with '/' or contains '..' after expansion from the cask stanza; an empty or placeholder filename that resolves to zero components.

Common situations: Hand-written casks with absolute font paths; unresolved template variables leaving '.'/'..' fragments; malformed font stanzas in third-party taps.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/3a7706c610ed3763. Report an issue: GitHub.