jdx/mise · error

brew-cask: invalid structured flight path '{}'

Error message

brew-cask: invalid structured flight path '{}'

What it means

`validate_flight_relative_path` rejects flight paths that are absolute or contain a `..` (ParentDir) component. It is the traversal guard applied to every path joined onto the staged root, so structured steps cannot reach files outside the staging sandbox.

Source

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

        .replace("{{staged_path}}", &staged_path.to_string_lossy())
        .replace("{{appdir}}", &appdir.to_string_lossy());
    if let Some(version) = version {
        value = value.replace("{{version}}", version);
    }
    if let Some(rest) = value.strip_prefix("~/") {
        value = crate::dirs::HOME.join(rest).to_string_lossy().to_string();
    }
    value
}

fn validate_flight_relative_path(path: &str) -> Result<()> {
    let path = Path::new(path);
    if path.is_absolute()
        || path
            .components()
            .any(|component| matches!(component, Component::ParentDir))
    {
        bail!(
            "brew-cask: invalid structured flight path '{}'",
            path.display()
        );
    }
    Ok(())
}

fn expand_braces(pattern: &str) -> Vec<String> {
    let Some(start) = pattern.find('{') else {
        return vec![pattern.to_string()];
    };
    let Some(end_offset) = pattern[start + 1..].find('}') else {
        return vec![pattern.to_string()];
    };
    let end = start + 1 + end_offset;
    let prefix = &pattern[..start];
    let suffix = &pattern[end + 1..];
    let mut expanded = Vec::new();

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Rewrite the path relative to the staged root with no `..` components
  2. Use an artifact form and base that legitimately supports the location instead of smuggling absolute paths
  3. Sanitize template output before it lands in a staged-relative field

Example fix

# before
move(source: "../../shared/lib.dylib", target: "lib/lib.dylib")
# after
move(source: "shared/lib.dylib", target: "lib/lib.dylib")
Defensive patterns

Strategy: validation

Validate before calling

// Reject absolute or parent-escaping relative paths before they reach the resolver
fn is_safe_relative_path(p: &str) -> bool {
    let path = std::path::Path::new(p);
    !path.is_absolute()
        && !path
            .components()
            .any(|c| matches!(c, std::path::Component::ParentDir))
}

Try / catch

if err.to_string().contains("invalid structured flight path") {
    // rewrite the offending path staged-relative; do not attempt to whitelist `..` segments
}

Prevention

When it happens

Trigger: A cask stanza path like `../shared/lib.x` or `/Applications/Foo.app` where a staged-relative path is required; a template expanding to a value that begins with `/`; concatenation bugs leaving `..` segments in the string.

Common situations: Porting ruby stanzas that use absolute paths; a user-edited cask trying to share payloads across casks; version strings injecting a leading separator.

Related errors


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