getzola/zola · critical

Failed to parse {} page(s): {msg}

Error message

Failed to parse {} page(s):
{msg}

What it means

During site `load`, Zola parses all content pages in parallel and collects per-file parse errors. If any page fails to parse, `load` aborts and returns this anyhow error aggregating the count of failed pages and a bulleted list of `path: error` messages.

Source

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

            }
        }
        let results: Vec<(PathBuf, Result<Page>)> = page_paths
            .par_iter()
            .map(|p| (p.clone(), Page::from_file(p, &self.config, &self.base_path)))
            .collect();
        let (pages, errors): (Vec<_>, Vec<_>) = results.into_iter().partition(|(_, r)| r.is_ok());

        if !errors.is_empty() {
            let mut errors: Vec<_> = errors.into_iter().map(|(p, r)| (p, r.unwrap_err())).collect();
            // sort by path for deterministic output
            errors.sort_by(|(a, _), (b, _)| a.cmp(b));

            let msg = errors
                .iter()
                .map(|(p, e)| format!("  - {}: {e}", p.display()))
                .collect::<Vec<_>>()
                .join("\n");
            return Err(anyhow!("Failed to parse {} page(s):\n{msg}", errors.len()));
        }

        let pages: Vec<Page> = pages.into_iter().map(|(_, r)| r.unwrap()).collect();
        self.create_default_index_sections()?;

        for page in pages {
            // should we skip drafts?
            if page.meta.draft && !self.include_drafts {
                continue;
            }

            // We are only checking it on load and not in add_page since we have access to
            // all the components there.
            if page.file.filename == "index.md" {
                let is_invalid = match page.components.last() {
                    Some(_) => sections.contains(&page.components.join("/")),
                    // content/index.md is always invalid, but content/colocated/index.md is ok
                    None => page.file.colocated_path.is_none(),

View on GitHub (pinned to 61d3082821)

Solutions

  1. Read the per-file messages listed under the summary (each ' - <path>: <error>' line) and fix the first listed file's front-matter/markdown syntax
  2. Validate front matter delimiters match (+++ for TOML, --- for YAML) and are closed
  3. Check field types against Zola's page config schema (e.g. dates as strings in TOML, template as string)
  4. Run `zola build` after each fix to see remaining failures

Example fix

// before (content/post.md)
+++
title = Broken quote
date = 2024-01-01
// after
+++
title = "Broken quote"
date = "2024-01-01"
Defensive patterns

Strategy: validation

Validate before calling

import Toml from '@iarna/toml';
import fs from 'fs';
export function validateFrontMatter(file) {
  const text = fs.readFileSync(file, 'utf8');
  const m = text.match(/^\+\+\+([\s\S]*?)\+\+\+/);
  if (!m) throw new Error(`${file}: missing/closed +++ front matter`);
  try { Toml.parse(m[1]); } catch (e) { throw new Error(`${file}: ${e.message}`); }
}
contentFiles().forEach(validateFrontMatter);

Type guard

function hasValidDelimiters(text) {
  const m = text.match(/^(\+\+\+|---)([\s\S]*?)^\1/m);
  return m != null;
}

Try / catch

match site.load() {
    Ok(_) => build(site),
    Err(e) if e.to_string().starts_with("Failed to parse ") => {
        eprintln!("{e:#}"); // prints the per-file bullet list for fixing
        std::process::exit(1);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Any content file under the `content/` directory that fails front-matter or markdown parsing while building/serving — e.g. invalid TOML/YAML front matter, unclosed delimiters, wrong front-matter format — causing the `errors` map in `load` to be non-empty.

Common situations: Malformed TOML in a page's front matter (missing quotes, wrong types like string vs integer for a config field); YAML tabs; forgetting to close `+++`/`---` delimiters; a partially-edited or merged content file with syntax errors; wrong front-matter language marker for the site config.

Understand the failure class

Related errors


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