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
- Verify the glob pattern against the actual staged directory contents for the version being installed.
- Update the pattern or template variable ({{version}}, {{arch}}) to match the new artifact names.
- 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
- Dry-run glob expansion against the staged path before install.
- Update glob patterns when upstream renames binaries between versions.
- Make optional links conditional with if_exists guards.
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
- brew-cask: structured symlink source '{}' did not match any
- brew-cask: structured symlink globs must use staged_path
- brew-cask: staged symlink path escaped extraction root: {}
- brew-cask: refusing generic artifact source outside the extr
- brew-cask: installer executable '{}' was not found
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/ec5f889d1924935a.
Report an issue: GitHub.