jdx/mise · error

brew-cask: structured symlink source '{}' did not match any

Error message

brew-cask: structured symlink source '{}' did not match any paths

What it means

A brew-cask structured symlink step uses a glob source (source_glob=true) whose expansion matched zero paths inside the staged application bundle. Since there is nothing to link, the step fails rather than creating an empty or dangling directory target.

Source

Thrown at src/system/packages/brew/cask/flight.rs:709

            // transaction backup is sufficient for rollback; recording them
            // would fingerprint their contents and force later reinstalls.
        }
        FlightStep::Symlink {
            source,
            target,
            force,
            uninstall,
            source_glob,
            sudo,
            guards,
        } => {
            if !flight_guards_pass(cask, guards, staged_path, appdir)? {
                return Ok(());
            }
            let target = resolve_flight_path_with_context(cask, target, staged_path, appdir)?;
            let sources = flight_symlink_sources(cask, source, *source_glob, staged_path, appdir)?;
            if sources.is_empty() {
                bail!(
                    "brew-cask: structured symlink source '{}' did not match any paths",
                    source.path
                );
            }
            let target_metadata = target.symlink_metadata().ok();
            let target_is_real_dir = target_metadata
                .as_ref()
                .is_some_and(|metadata| metadata.is_dir());
            let target_is_dir = target_is_real_dir || sources.len() > 1;
            if sources.len() > 1 {
                let created_external_directory =
                    target_metadata.is_none() && !target.starts_with(staged_path);
                if target_metadata.is_some() && !target_is_real_dir {
                    if target.exists() && !force && !targets.previous_symlinks.contains(&target) {
                        bail!(
                            "brew-cask: structured symlink target '{}' already exists",
                            target.display()
                        );

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Verify the glob pattern against the actual staged directory contents for the version being installed.
  2. Update the pattern or template variable ({{version}}, {{arch}}) to match the new artifact names.
  3. Make the step conditional with a guard (if_exists on the expected file) if the source is legitimately optional.

Example fix

// before
source: { path: "bin/*-cli", glob: true }
// after
source: { path: "bin/myapp-cli-{{arch}}", glob: true }
Defensive patterns

Strategy: validation

Validate before calling

let sources = flight_symlink_sources(cask, source, true, staged_path, appdir)?;
if sources.is_empty() {
    eprintln!("warning: symlink glob {} matched nothing", source.path);
}

Prevention

When it happens

Trigger: FlightStep::Symlink with source_glob=true where the pattern (template-expanded against staged_path) matches nothing — binary/CLI name changed in a new version, optional component not shipped, or a wrong glob base (see related staged_path requirement).

Common situations: Upstream renamed bundled executables between versions; a glob written for one app layout applied to another; installing on a platform/arch where that staged file is absent.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/ec5f889d1924935a. Report an issue: GitHub.