How Keystone checks your book
Keystone is a compiler for books, and like any compiler it checks your source as it builds. When something is wrong it tells you — on the terminal, naming the element — instead of silently letting it through.
This page is the map. Hit a message on the terminal? Find its row below and follow it to a page with the exact message and how to fix it.
Two outcomes: warnings and errors
Every Keystone diagnostic is one of two severities.
WARN:— something is off, but the build has a safe fallback. The element is dropped or its bad input ignored, and you still get an artifact — unless you've enabled strict mode, where any warning fails the build.ERROR:— the build cannot proceed correctly, so it stops and writes no artifact.
Most diagnostics are Keystone's own, prefixed WARN: or ERROR:. A few come
from the tools underneath — Pandoc reading your Markdown, fetching an image, or
resolving a citation — and print in Pandoc's own [WARNING] … format instead
(their rows are marked (Pandoc) below). They're warnings all the same; strict
mode fails on them too.
Where checks happen
Your book passes through stages — reading your Markdown, expanding shortcuts, running the handlers, composing the running heads and feet, converting math, and resolving citations, images, and configuration — and each can fail in its own way. Find the row whose message matches yours:
| Build stage | What can go wrong | A message you'll see | Severity |
|---|---|---|---|
| Reading your Markdown | Unclosed div | Div at … unclosed … |
WARN |
| Reading your Markdown | A malformed fence or unclosed span | (nothing — silent) | — |
| Expanding shortcuts | Unrecognized class | Unrecognized class '…' |
WARN |
| Expanding shortcuts | Unrecognized attribute | ignores unrecognized attributes |
WARN |
| Expanding shortcuts | Missing required field | Shortcut '…' requires … |
ERROR |
| Running a handler | Invalid attribute value | unrecognized size · unknown type · invalid cols |
WARN |
| Running a handler | Undeclared mark | mark '…' is not declared |
ERROR |
| Running heads & feet | Unknown placeholder | unrecognized placeholder '{…}' |
WARN |
| Running heads & feet | Header/footer text suppressed | …-text suppressed |
WARN |
| Converting math | Math that can't convert | equation(s) cannot be converted |
ERROR |
| Resolving citations (Pandoc) | Undefined citation | Citeproc: citation … not found |
WARN |
| Fetching images (Pandoc) | Image not found | Could not fetch resource … |
WARN |
| Resolving configuration | Missing or invalid metadata | Missing required metadata fields · draft-scale must be… |
ERROR |
The message column is a representative fragment, not the exact text. Handler
warnings in particular share the shape <handler>: <problem> '<value>' — so
font: unknown family 'garmond' is the Running a handler row even though its
words aren't listed. Match on the stage and the shape, not a literal string.
Finding the offender
A compiler usually points at a file and line number. Keystone can't — not yet. It builds on Pandoc, whose Markdown reader doesn't record where each element came from in your source, so there is no line for Keystone to report. Keystone will surface real line numbers as soon as Pandoc can supply them for Markdown.
Until then, every message names the offending element with a compact selector you can search for — its classes, its identifier, and a snippet of its leading text:
WARN: aside: unknown type 'todo' (in .aside "A callout whose type is not one of the d…")
That (in …) is your search key. Search your source for the quoted class, the
identifier, or the leading-text snippet — in the manuscript for a content
mistake, or in shortcuts.yaml and your metadata for a configuration one.
Strict mode
While you're drafting, a warning shouldn't stop you — you want to see the page even with a placeholder that isn't quite right. So by default warnings are lenient: they print and the build continues.
Before you publish, flip that around. Set KEYSTONE_WARNINGS_AS_ERRORS=true in
project.conf and every warning becomes
fatal:
ERROR: warnings-as-errors is enabled and the build produced warnings:
vspace: unrecognized size 'banana'
No new artifact was written. Fix the warnings above, or unset KEYSTONE_WARNINGS_AS_ERRORS for a lenient build
For a one-off check without editing config, make publish strict=true builds
once in strict mode — see Publishing your book.
Strict mode fails the build on any warning and promotes no artifact — nothing
half-built ever lands in artifacts/. Where it can, it collects a run's warnings
and reports them together rather than stopping at the first, so you fix them in
one pass. Draft lenient, publish strict.
Silent by design
Not everything absent is a mistake. A few things are meant to be optional, so their absence is never reported:
- Optional attribution. An epigraph or pull-quote with no
sourceis a quote without an attribution line — a normal choice, not an error. - Undefined conditional symbols.
ifdef/ifndefgate on whether a symbol is defined; an undefined symbol is simply false, so the content is omitted. That's the whole mechanism, not a failure. See Conditional content.
Separately, there is a small set of mistakes Keystone cannot see at all — malformed markup that never becomes an element. Know the limits; they matter as much as the checks themselves.
Under the hood
How the checks are implemented — the closed vocabulary, the shared diagnostic
path, and how a core template forker adds their own — is in
Validation & diagnostics.