zed-industries/zed · error · anyhow::Error
destination path has no parent: {destination_path:?}
Error message
destination path has no parent: {destination_path:?} What it means
download_server_binary needs a parent directory next to the destination to create a staging path (for extraction/verification before an atomic rename). Rust's Path::parent() returns None only for the empty path and the filesystem root '/', so this bail fires when destination_path is '' or '/'.
Source
Thrown at crates/http_client/src/github_download.rs:52
let metadata_content = serde_json::to_string(self)
.with_context(|| format!("serializing metadata for {metadata_path:?}"))?;
async_fs::write(metadata_path, metadata_content.as_bytes())
.await
.with_context(|| format!("writing metadata file at {metadata_path:?}"))?;
Ok(())
}
}
pub async fn download_server_binary(
http_client: &dyn HttpClient,
url: &str,
digest: Option<&str>,
destination_path: &Path,
asset_kind: AssetKind,
) -> Result<(), anyhow::Error> {
log::info!("downloading github artifact from {url}");
let Some(destination_parent) = destination_path.parent() else {
anyhow::bail!("destination path has no parent: {destination_path:?}");
};
let staging_path = staging_path(destination_parent, asset_kind)?;
let mut response = http_client
.get(url, Default::default(), true)
.await
.with_context(|| format!("downloading release from {url}"))?;
let body = response.body_mut();
if let Err(err) = extract_to_staging(body, digest, url, &staging_path, asset_kind).await {
cleanup_staging_path(&staging_path, asset_kind).await;
return Err(err);
}
if let Err(err) = finalize_download(&staging_path, destination_path).await {
cleanup_staging_path(&staging_path, asset_kind).await;
return Err(err);
}View on GitHub (pinned to f4178619ac)
Solutions
- Build the destination from a guaranteed base: PathBuf::from(env::var_os("HOME").ok_or(...)?).join("...")
- Validate destination_path is absolute, non-empty, and not the root before calling download_server_binary
- Log the offending path at the call site so the misconfigured variable is obvious
- Check the configuration source (settings file / env) that produced the empty path
Example fix
// before
let destination_path = Path::new(&config.install_dir);
download_server_binary(&http, url, digest, destination_path, asset_kind).await?;
// after
let base = dirs::data_dir().context("no data dir")?;
let destination_path = base.join("server").join(binary_file_name);
assert!(destination_path.parent().is_some(), "invalid destination");
download_server_binary(&http, url, digest, &destination_path, asset_kind).await?; Defensive patterns
Strategy: validation
Validate before calling
fn valid_destination(path: &Path) -> bool {
!path.as_os_str().is_empty() && path.parent().is_some() && path != Path::new("/")
}
assert!(valid_destination(&destination_path)); Type guard
fn is_concrete_file_path(p: &Path) -> bool {
p.parent().is_some() // false for "" and "/"
} Prevention
- Always construct destinations via PathBuf::join from a validated base directory
- Fail fast when HOME/XDG_DATA_HOME lookups return None instead of stringifying empty values
- Unit-test path construction for empty/missing environment variables
When it happens
Trigger: Passing destination_path = Path::new("") or Path::new("/") — e.g. a joined path where every component was empty because a config dir resolved to None and was silently stringified, or an install root mistakenly given as the destination itself.
Common situations: HOME/environment variables unset so paths::data_dir()-style lookups produce empty strings; misconfigured install prefixes set to '/'; test code passing a bare filename placeholder instead of a full path.
Related errors
- extension dir {} is not an absolute path
- failed to run `git init` in directory '{}'
- Could not detect a working directory in the container. Set E
- Could not detect a working directory; set EVAL_CLI_WORKDIR v
- path dataset requires data_dir
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/a1c360e162f5c677.
Report an issue: GitHub.