{"record":{"id":"8b95159b24cfd52a","repo":"denoland/deno","slug":"invalid-output-dylib-path-has-no-parent-dir","errorCode":null,"errorMessage":"invalid --output: dylib path has no parent dir: {}","messagePattern":"invalid --output: dylib path has no parent dir: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":3005,"sourceCode":"    bail!(\n      \"invalid {kind} {name:?}: must match [A-Za-z0-9 ._-]+, but contains {c:?}\",\n    );\n  }\n  Ok(())\n}\n\n/// The pieces of `dylib_path` we feed into the bundlers, with proper\n/// error messages instead of `unwrap` panics on degenerate inputs like\n/// `--output /` or `--output .`.\nstruct DylibParts<'a> {\n  parent: &'a Path,\n  file_name: &'a std::ffi::OsStr,\n  app_name: String,\n}\n\nfn dylib_parts(dylib_path: &Path) -> Result<DylibParts<'_>, AnyError> {\n  let parent = dylib_path.parent().ok_or_else(|| {\n    deno_core::anyhow::anyhow!(\n      \"invalid --output: dylib path has no parent dir: {}\",\n      dylib_path.display()\n    )\n  })?;\n  let file_name = dylib_path.file_name().ok_or_else(|| {\n    deno_core::anyhow::anyhow!(\n      \"invalid --output: dylib path has no file name: {}\",\n      dylib_path.display()\n    )\n  })?;\n  let app_name = dylib_path\n    .file_stem()\n    .ok_or_else(|| {\n      deno_core::anyhow::anyhow!(\n        \"invalid --output: dylib path has no file stem: {}\",\n        dylib_path.display()\n      )\n    })?","sourceCodeStart":2987,"sourceCodeEnd":3023,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L2987-L3023","documentation":"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.","triggerScenarios":"Passing `deno desktop ... --output /` (or any path that normalizes to root) so dylib_path.parent() returns None.","commonSituations":"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.","solutions":["Pass a real file path under an existing directory, e.g. --output ./dist/libapp.dylib.","If the value comes from a script, default the variable when empty (OUT=\"./dist/app.dylib\") instead of letting it collapse to root.","Sanity-check with realpath that the argument is not the filesystem root before invoking the command."],"exampleFix":"# before\ndeno desktop compile --output \"$OUT_DIR/libapp.dylib\"   # OUT_DIR empty -> /libapp.dylib? or literal /\n# error: invalid --output: dylib path has no parent dir: /\n\n# after\nOUT_DIR=\"${OUT_DIR:-./dist}\"\ndeno desktop compile --output \"$OUT_DIR/libapp.dylib\"","handlingStrategy":"validation","validationCode":"# Rust callers can validate the dylib path before invoking the bundler\nfn has_parent(p: &std::path::Path) -> bool {\n    p.parent().map(|x| !x.as_os_str().is_empty()).unwrap_or(false)\n}\nassert!(has_parent(std::path::Path::new(&out_path)), \"--output must not be the filesystem root\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always default output variables in scripts (OUT=\"${OUT:-./dist/app.dylib}\") instead of letting them collapse to '/'.","Accept only fully-named file paths for --output, never directories or bare roots.","Run realpath on script-derived paths in CI to catch degenerate values before the tool does."],"tags":["cli","path","argument-validation","desktop"],"backgroundTag":"invalid-cli-path-argument","analyzedSha":"f7822238cab635a3a19f99f493f675fa81a7f9d8","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}