getzola/zola · error

could not parse domain `{}` from link

Error message

could not parse domain `{}` from link

What it means

`get_link_domain` parses an external link URL and extracts its host. When the URL parses successfully but has no host component (e.g. a relative or scheme-only URL such as `mailto:` or `data:`), the function bails with this message. It is used by `check_external_links` to group/validate external links by domain.

Source

Thrown at components/site/src/link_checking.rs:123

        );
    }
    messages
}

fn should_skip_by_prefix(link: &str, skip_prefixes: &[String]) -> bool {
    skip_prefixes.iter().any(|prefix| link.starts_with(prefix))
}

fn should_skip_by_file(file_path: &Path, glob_set: &GlobSet) -> bool {
    glob_set.is_match(file_path)
}

fn get_link_domain(link: &str) -> Result<String> {
    match Url::parse(link) {
        Ok(url) => match url.host_str().map(String::from) {
            Some(domain_str) => Ok(domain_str),
            None => bail!("could not parse domain `{}` from link", link),
        },
        Err(err) => bail!("could not parse domain `{}` from link: `{}`", link, err),
    }
}

/// Checks all external links and returns all the errors that were encountered.
/// Empty vec == all good
pub fn check_external_links(site: &Site) -> Vec<String> {
    struct LinkDef {
        file_path: PathBuf,
        external_link: String,
        domain: String,
    }

    impl LinkDef {
        pub fn new(file_path: &Path, external_link: &str, domain: String) -> Self {
            Self {
                file_path: file_path.to_path_buf(),
                external_link: external_link.to_string(),

View on GitHub (pinned to 61d3082821)

Solutions

  1. Filter out non-http(s) links before calling `get_link_domain` (skip `mailto:`, `tel:`, `data:`, anchors)
  2. Check that the link contains a host before parsing, e.g. starts with http:// or https://
  3. If the link is genuinely malformed, fix the content file where the link is defined

Example fix

// before
let domain = get_link_domain(link)?;
// after
if link.starts_with("mailto:") || link.starts_with("tel:") { continue; }
let domain = get_link_domain(link)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_external_http_link(link: &str) -> bool {
    matches!(Url::parse(link), Ok(ref u) if matches!(u.scheme(), "http" | "https") && u.host_str().is_some())
}

Type guard

fn has_host(url: &Url) -> bool { url.host_str().is_some() }

Try / catch

match get_link_domain(link) {
    Ok(domain) => check(domain),
    Err(_) => skipped_links.push(link.to_string()), // ignore non-domain links
}

Prevention

When it happens

Trigger: Calling `get_link_domain` with a link that `Url::parse` accepts but whose `url.host_str()` is None: scheme-only URLs like `mailto:user@example.com`, `tel:+123`, `data:...`, or protocol-relative/weird inputs that the url crate parses without a host.

Common situations: Site content contains `mailto:` or `tel:` links, anchor-only or data-URI links, or feed/generated links without an authority; the link checker treats them as unparseable domains.

Related errors


AI-assisted analysis of getzola/zola@61d3082821 (2026-09-03). Data as JSON: /api/errors/46dde354982aa74e. Report an issue: GitHub.