getzola/zola · error

Found broken external link(s)

Error message

Found {} broken external link(s)
{}

What it means

In check mode, Zola verifies external (http/https) links. If external_level = "error" and any external links fail to resolve (network error, 404, timeout), load fails with this message listing each broken URL.

Solutions

  1. Fix or remove the broken external URLs listed in the error output
  2. Set link_checker.external_level = "warn" in config.toml so broken links warn instead of failing
  3. Run the check on a machine/CI job with working internet access
  4. Exclude unreachable-by-design hosts if the checker offers ignore/skip options, or replace links with a stable archive URL

Example fix

// before: config.toml
[link_checker]
external_level = "error"
// after
[link_checker]
external_level = "warn"
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-check critical external URLs before a release build:
// curl -fsSL -o /dev/null --max-time 10 https://example.com/page || echo BROKEN

Try / catch

// Use warn level so flaky external hosts don't fail builds:
// [link_checker]
// external_level = "warn"
match result {
    Err(e) if e.to_string().contains("broken external link") => {
        log::warn!("continuing despite external link failures: {e}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: zola check with check_external_links enabled and a linked external URL returns a non-success status or cannot be reached; external_level = "error" in config link_checker.

Common situations: Dead external links after third-party sites moved or shut down; CI running checks without network access; rate-limited or bot-blocked hosts (e.g. GitHub, social media) returning 4xx/5xx; temporary network outages.

Related errors


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

Appendix: source

Thrown at components/site/src/lib.rs:389

        }

        // check external links, log the results, and error out if needed
        if self.config.is_in_check_mode() && self.check_external_links {
            let external_link_messages = link_checking::check_external_links(self);
            if !external_link_messages.is_empty() {
                let messages: Vec<String> = external_link_messages
                    .iter()
                    .enumerate()
                    .map(|(i, msg)| format!("  {}. {}", i + 1, msg))
                    .collect();
                let msg = format!(
                    "Found {} broken external link(s)\n{}",
                    messages.len(),
                    messages.join("\n")
                );
                match self.config.link_checker.external_level {
                    config::LinkCheckerLevel::Warn => log::warn!("{msg}"),
                    config::LinkCheckerLevel::Error => return Err(anyhow!(msg)),
                }
            }
        }

        Ok(())
    }

    /// Insert a default index section for each language if necessary so we don't need to create
    /// a _index.md to render the index page at the root of the site
    pub fn create_default_index_sections(&mut self) -> Result<()> {
        let mut missing_sections = Vec::new();
        for (index_path, lang) in self.index_section_paths() {
            if let Some(index_section) = self.library.sections.get(&index_path)
                && self.config.build_search_index
                && !index_section.meta.in_search_index
            {
                bail!(
                    "You have enabled search in the config but disabled it in the index section: \

View on GitHub (pinned to 61d3082821)