jdx/mise · error
brew-cask: structured directory copy requires recursive=true
Error message
brew-cask: structured directory copy requires recursive=true
What it means
A structured copy step whose source is a directory requires `recursive: true`; without it the step would silently copy an empty directory entry, so it is rejected. This mirrors `cp` semantics where copying a directory needs `-r`.
Solutions
- Add `recursive = true` to the copy step in the cask definition
- If only a single file was intended, correct the source path to the file rather than its directory
- Verify with `ls` whether the staged source is a directory before choosing flags
Example fix
// before
{ copy: { source: "App.app", target: "/Applications/App.app" } }
// after
{ copy: { source: "App.app", target: "/Applications/App.app", recursive: true } } Defensive patterns
Strategy: validation
Validate before calling
let src = staged.join(source);
if src.is_dir() && !recursive {
return Err("directory source requires recursive=true");
} Type guard
fn copy_flags_ok(src: &Path, recursive: bool) -> bool { !src.is_dir() || recursive } Prevention
- Always set recursive=true when copying bundles (.app, .framework)
- Lint cask copy stanzas: directory source implies recursive
- Check source type with `test -d` when authoring stanzas
When it happens
Trigger: `execute_flight_step` Copy step where `source.is_dir()` is true but the step's `recursive` flag is false/absent in the cask stanza.
Common situations: A cask stanza copies a framework or app bundle directory but omits `recursive = true`; a stanza written for a single file was repointed at a directory after an upstream restructure.
Understand the failure class
Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.
Related errors
- brew-cask: structured copy source must resolve to exactly…
- brew-cask: structured copy source
- brew-cask: structured copy target
- brew-cask: structured move with multiple sources requires a…
- ditto failed copying
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/837fd4c1bb44c3db.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask/flight.rs:697
overwrite,
source_glob,
guards,
} => {
if !flight_guards_pass(cask, guards, staged_path, appdir)? {
return Ok(());
}
let sources = flight_symlink_sources(cask, source, *source_glob, staged_path, appdir)?;
let [source] = sources.as_slice() else {
bail!("brew-cask: structured copy source must resolve to exactly one path");
};
if !source.exists() {
bail!(
"brew-cask: structured copy source '{}' was not found",
source.display()
);
}
if source.is_dir() && !recursive {
bail!("brew-cask: structured directory copy requires recursive=true");
}
let target = resolve_flight_path_with_context(cask, target, staged_path, appdir)?;
let external = !target.starts_with(staged_path);
let target_metadata = target.symlink_metadata().ok();
if target_metadata.is_some() {
if !overwrite {
bail!(
"brew-cask: structured copy target '{}' already exists",
target.display()
);
}
if external {
targets.protect(&target)?;
} else {
file::remove_all(&target)?;
}
}
if let Some(parent) = target.parent() {View on GitHub (pinned to 533346cc37)