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
- Read the per-file messages listed under the summary (each ' - <path>: <error>' line) and fix the first listed file's front-matter/markdown syntax
- Validate front matter delimiters match (+++ for TOML, --- for YAML) and are closed
- Check field types against Zola's page config schema (e.g. dates as strings in TOML, template as string)
- 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
- Run `zola build` (or a CI content-lint step) on every commit so parse errors surface immediately
- Keep front matter delimiters consistent (+++ TOML / --- YAML) and closed on their own line
- Quote all string front-matter values and check field types against the Zola docs schema
- Enable editor TOML/YAML syntax highlighting for the front-matter block to catch typos early
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Error parsing YAML datetime
- SASS path conflict: "{}" and "{}" both compile to "{}"
- Couldn't lock imageproc (process_images)
AI-assisted analysis of getzola/zola@61d3082821 (2026-09-03).
Data as JSON: /api/errors/fc2c670b7dce3f52.
Report an issue: GitHub.