jdx/mise · error
brew-cask: structured symlink globs must use staged_path
Error message
brew-cask: structured symlink globs must use staged_path
What it means
`flight_symlink_sources` only implements glob expansion against the staged cask directory. A copy or symlink step with `source_glob: true` whose source base is `AppDir`, `HomebrewPrefix` or `Literal` is rejected before any glob runs: only `FlightPathBase::StagedPath` is valid for globbed sources.
Source
Thrown at src/system/packages/brew/cask.rs:3854
FlightGuard::IfExists(path) => {
Ok(resolve_flight_path_with_context(cask, path, staged_path, appdir)?.exists())
}
FlightGuard::UnlessExists(path) => {
Ok(!resolve_flight_path_with_context(cask, path, staged_path, appdir)?.exists())
}
}
}
fn flight_symlink_sources(
cask: &Cask,
source: &FlightPath,
source_glob: bool,
staged_path: &Path,
appdir: &Path,
) -> Result<Vec<PathBuf>> {
if source_glob {
if source.base != FlightPathBase::StagedPath {
bail!("brew-cask: structured symlink globs must use staged_path");
}
let pattern = expand_flight_template(cask, &source.path, staged_path, appdir);
return expand_staged_glob(staged_path, &pattern);
}
Ok(vec![resolve_flight_path_with_context(
cask,
source,
staged_path,
appdir,
)?])
}
fn create_flight_symlink(source: &Path, target: &Path, sudo: FlightSudo) -> Result<()> {
match sudo {
FlightSudo::Never => file::make_symlink(source, target).map(|_| ()),
FlightSudo::IfNeeded => make_symlink_elevating(source, target),
FlightSudo::Always => sudo::run("/bin/ln", &symlink_command_args(source, target), &[]),
}View on GitHub (pinned to 6f52dcdf99)
Solutions
- Drop the glob metacharacters and use a literal path with the non-staged base
- Keep the glob but express the source relative to the staged payload (StagedPath base)
- Restructure the artifact so only staged-payload files are ever globbed
Example fix
# before
symlink(source: "#{appdir}/*.app/Contents/MacOS/tool", source_glob: true, target: "#{prefix}/bin/tool")
# after - glob runs against the staged payload
symlink(source: "*.app/Contents/MacOS/tool", source_glob: true, target: "#{prefix}/bin/tool") Defensive patterns
Strategy: type-guard
Type guard
// Narrow FlightPath values before combining a glob with a base
fn glob_source_is_supported(source: &FlightPath, source_glob: bool) -> bool {
!source_glob || matches!(source.base, FlightPathBase::StagedPath)
} Try / catch
if err.to_string().contains("symlink globs must use staged_path") {
// strip the glob and use a literal path, or rebase the source onto the staged payload
} Prevention
- Never prefix glob patterns with appdir or absolute prefixes
- Lint cask stanzas for glob metacharacters in non-staged sources
- Keep wildcards scoped to the staged payload only
When it happens
Trigger: A cask stanza combining a non-staged base (an `$APPDIR`/`#{appdir}`-anchored source) with glob metacharacters; programmatic construction of a FlightPath with a non-staged base and `source_glob: true`.
Common situations: Hand-written or ported Homebrew ruby stanzas that glob absolute or appdir paths; templating that prefixes the appdir onto a wildcard pattern.
Related errors
- brew-cask: structured symlink source '{}' did not match any
- brew-cask: structured symlink source '{}' did not match any
- brew-cask: staged symlink path escaped extraction root: {}
- brew-cask: refusing generic artifact source outside the extr
- brew-cask: refusing to restore flight target through a chang
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/4d69792d3c3fc2fa.
Report an issue: GitHub.