denoland/deno · error

invalid --output: dylib path has no parent dir

Error message

invalid --output: dylib path has no parent dir: {}

What it means

DylibParts decomposes the --output dylib path (parent dir, file name, app name) to feed the platform bundlers, replacing what used to be unwrap() panics with proper errors. Path::parent() is None only for the filesystem root, so this error means --output resolved to '/' — there is no directory to place the bundle next to the dylib.

Solutions

  1. Pass a real file path under an existing directory, e.g. --output ./dist/libapp.dylib.
  2. If the value comes from a script, default the variable when empty (OUT="./dist/app.dylib") instead of letting it collapse to root.
  3. Sanity-check with realpath that the argument is not the filesystem root before invoking the command.

Example fix

# before
deno desktop compile --output "$OUT_DIR/libapp.dylib"   # OUT_DIR empty -> /libapp.dylib? or literal /
# error: invalid --output: dylib path has no parent dir: /

# after
OUT_DIR="${OUT_DIR:-./dist}"
deno desktop compile --output "$OUT_DIR/libapp.dylib"
Defensive patterns

Strategy: validation

Validate before calling

# Rust callers can validate the dylib path before invoking the bundler
fn has_parent(p: &std::path::Path) -> bool {
    p.parent().map(|x| !x.as_os_str().is_empty()).unwrap_or(false)
}
assert!(has_parent(std::path::Path::new(&out_path)), "--output must not be the filesystem root");

Prevention

When it happens

Trigger: Passing `deno desktop ... --output /` (or any path that normalizes to root) so dylib_path.parent() returns None.

Common situations: A build script interpolates an unset output variable that collapses to '/'; shell quoting accident (--output / when a variable was empty and the path joined against root); deliberately probing degenerate inputs.

Related errors


AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20). Data as JSON: /api/errors/8b95159b24cfd52a. Report an issue: GitHub.

Appendix: source

Thrown at cli/tools/desktop.rs:3005

    bail!(
      "invalid {kind} {name:?}: must match [A-Za-z0-9 ._-]+, but contains {c:?}",
    );
  }
  Ok(())
}

/// The pieces of `dylib_path` we feed into the bundlers, with proper
/// error messages instead of `unwrap` panics on degenerate inputs like
/// `--output /` or `--output .`.
struct DylibParts<'a> {
  parent: &'a Path,
  file_name: &'a std::ffi::OsStr,
  app_name: String,
}

fn dylib_parts(dylib_path: &Path) -> Result<DylibParts<'_>, AnyError> {
  let parent = dylib_path.parent().ok_or_else(|| {
    deno_core::anyhow::anyhow!(
      "invalid --output: dylib path has no parent dir: {}",
      dylib_path.display()
    )
  })?;
  let file_name = dylib_path.file_name().ok_or_else(|| {
    deno_core::anyhow::anyhow!(
      "invalid --output: dylib path has no file name: {}",
      dylib_path.display()
    )
  })?;
  let app_name = dylib_path
    .file_stem()
    .ok_or_else(|| {
      deno_core::anyhow::anyhow!(
        "invalid --output: dylib path has no file stem: {}",
        dylib_path.display()
      )
    })?

View on GitHub (pinned to f7822238ca)