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 structured `symlink` step found no source paths. Sources resolve through `flight_symlink_sources`: with `source_glob: true` the template-expanded pattern is globbed under the staged path, and an empty result is fatal because a link cannot be created from nothing. All `guards` must have matched for execution to reach this check.

Source

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

            force,
            uninstall,
            source_glob,
            sudo,
            guards,
        } => {
            if !guards
                .iter()
                .map(|guard| flight_guard_matches(cask, guard, staged_path, appdir))
                .collect::<Result<Vec<_>>>()?
                .into_iter()
                .all(|matches| matches)
            {
                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 6f52dcdf99)

Solutions

  1. List the staged directory and correct the source pattern to the actual file name
  2. Template the version-dependent segments so the pattern tracks releases
  3. Guard optional symlinks with `if_exists` so absent sources skip instead of fail
  4. Re-stage the payload if extraction may have been partial

Example fix

# before
symlink(source: "mytool-1.*/bin/mytool", source_glob: true, target: "#{prefix}/bin/mytool")
# after
symlink(source: "mytool-#{version}/bin/mytool", source_glob: true, target: "#{prefix}/bin/mytool")
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check symlink glob sources match at least one path
let sources = flight_symlink_sources(cask, &step.source, step.source_glob, staged_path, appdir)?;
if sources.is_empty() {
    return Err(eyre!("symlink source '{}' matched nothing under staged payload", step.source.path));
}

Try / catch

if err.to_string().contains("symlink source") && err.to_string().contains("did not match any paths") {
    // dump the staged directory tree to pinpoint the renamed file
}

Prevention

When it happens

Trigger: `symlink` with `source_glob: true` matching zero files in the staged payload; a version-stamped source template expanding to a name that no longer exists; the binary was renamed upstream.

Common situations: Cask version bump changing binary names; archive layout change between releases; typo or wrong letter-case in the glob.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/4a06a0aff06433ea. Report an issue: GitHub.