astrid-runtime/astrid · error

signed source URL cannot contain path segments

Error message

signed source URL cannot contain path segments

What it means

fetch_signed_member builds the remote URL for a signed-source member (Distro.lock or its .sig) by taking the distro URL, popping its last path segment, and appending the member file name. `Url::path_segments_mut()` returns Err(()) only when the URL cannot have path segments — i.e. it is a cannot-be-a-base URL (no hierarchical path, e.g. `mailto:` or a URL with an empty host/opaque path). The library throws this because it cannot safely join a file name onto such a URL.

Source

Thrown at crates/astrid-cli/src/commands/init_signed_source.rs:255

    let manifest_path = Path::new(source);
    if manifest_path.exists() && manifest_path.is_file() {
        let path = manifest_path
            .parent()
            .ok_or_else(|| anyhow::anyhow!("Distro.toml has no parent directory"))?
            .join(file_name);
        return std::fs::read(&path)
            .with_context(|| format!("failed to read signed source member {}", path.display()));
    }

    if offline {
        bail!(
            "--offline: signed source member {file_name} is not local and network access is forbidden"
        );
    }

    let mut url = url::Url::parse(&super::resolve_distro_url(source)?)?;
    url.path_segments_mut()
        .map_err(|()| anyhow::anyhow!("signed source URL cannot contain path segments"))?
        .pop()
        .push(file_name);
    fetch_url_bytes(url.as_str(), file_name, 1024 * 1024).await
}

async fn fetch_url_bytes(url: &str, name: &str, limit: usize) -> anyhow::Result<Vec<u8>> {
    let client = reqwest::Client::builder()
        .user_agent("astrid-cli")
        .timeout(std::time::Duration::from_secs(30))
        .build()?;
    let response = client
        .get(url)
        .send()
        .await
        .with_context(|| format!("failed to fetch {name}"))?;
    if !response.status().is_success() {
        bail!(
            "failed to fetch {name} from {url} (HTTP {})",

View on GitHub (pinned to affd8760f4)

Solutions

  1. Fix the distro source URL so it is a standard http(s) URL with scheme://host/path (e.g. `https://mirror.example/distro/`)
  2. Run the URL through url::Url::parse and check `url.cannot_be_a_base()` before fetching to fail fast with a clearer message
  3. Verify resolve_distro_url output for the given source value; if a config mapping produced the bad URL, correct the mapping

Example fix

// before
let source = "astrid:mirror"; // cannot-be-a-base -> error
// after
let source = "https://mirror.example.com/distro/"; // path_segments_mut works
Defensive patterns

Strategy: validation

Validate before calling

let url = url::Url::parse(&resolve_distro_url(source)?)?;
if url.cannot_be_a_base() {
    anyhow::bail!("distro source URL must be an http(s) URL with a host and path: {source}");
}

Type guard

fn is_joinable_url(s: &str) -> bool {
    url::Url::parse(s).map(|u| !u.cannot_be_a_base()).unwrap_or(false)
}

Try / catch

match fetch_signed_member(source, offline, file_name).await {
    Ok(bytes) => bytes,
    Err(e) if e.to_string().contains("cannot contain path segments") => {
        eprintln!("Bad distro source URL (needs scheme://host/path): {source}"); std::process::exit(2);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling fetch_signed_manifest (which calls fetch_signed_member) when `source` resolves, via resolve_distro_url, to a cannot-be-a-base URL such as a malformed scheme-only URL (e.g. `astrid:` with no path/host) or an opaque URL. A well-formed http(s) URL never triggers this.

Common situations: A typo'd or hand-edited distro source in Distro.toml or CLI config where the URL lacks a host (e.g. `https:/mirror.example/distro/` missing a slash, or a bare scheme), producing an opaque/cannot-be-a-base URL.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/b8afc8a398fdea63. Report an issue: GitHub.