Validating Manifests
Validate a PanelWave manifest with AJV in Node.js or the PanelWave CLI, and learn how to read the most common validation errors.
Every PanelWave manifest should be validated against the official schema before it is published or handed to the player. There are two supported paths: the @panelwave/cli command line tool, and AJV directly in your own code.
Option 1: PanelWave CLI (recommended)
npm install -g @panelwave/cli
panelwave validate ./my-comic/panelwave.json
The CLI is published on npm as @panelwave/cli and validates against a bundled copy of the schema, so it works offline. The bundled copy is guaranteed to match the format version the CLI release was built against (1.6.0 in CLI 1.1.0, the current npm release; the current format is 1.7.0; 1.5.0 in CLI 1.0.0) — see CLI → Bundled schema.
Options:
| Option | Default | Description |
|---|---|---|
-s, --schema <version> | 1.0.0 | Schema version to validate against (resolved by major version to the bundled schema/<major>.0/panelwave.schema.json) |
--strict | off | Also fail (exit code 1) when there are warnings |
--json | off | Machine-readable output: { valid, errors, warnings } |
The exit code is 0 when valid, 1 otherwise — suitable for CI. Errors are grouped by JSON path:
✗ my-comic/panelwave.json has 2 error(s)
/meta
→ must have required property 'default_locale'
/chapters/0/panels/p1/layers/0
→ must have required property 'kind'
Warnings
Beyond schema errors, the CLI emits non-blocking structural warnings:
- No
assetssection — panels referencingassetIds will fail at runtime. - No
charactersinmeta— speech bubbles with acharacterIdwill be unresolved.
With --strict, warnings also fail the run.
Option 2: AJV programmatically
The schema uses JSON Schema 2020-12, so import AJV's 2020 build (ajv/dist/2020), and add ajv-formats for uri, date, and date-time format checks:
npm install ajv ajv-formats
Get the schema file itself from the panelwave/schema repository (or reuse the copy shipped inside @panelwave/cli at node_modules/@panelwave/cli/schema/1.0/panelwave.schema.json). Load it from disk: the $id URL https://panelwave.org/schema/1.0/panelwave.schema.json identifies the schema but is not publicly served yet, so don't fetch it at runtime.
const Ajv = require('ajv/dist/2020');
const addFormats = require('ajv-formats');
const ajv = new Ajv({
allErrors: true, // report every error, not just the first
verbose: true,
strict: false, // the schema uses 2020-12 features AJV strict mode flags
validateFormats: true,
allowUnionTypes: true
});
addFormats(ajv);
const schema = require('./schema/1.0/panelwave.schema.json');
const manifest = require('./my-comic/panelwave.json');
const validate = ajv.compile(schema);
if (validate(manifest)) {
console.log('Manifest is valid');
} else {
console.error(validate.errors);
}
Using the default new Ajv() (draft-07) build will fail to compile the schema. Always import ajv/dist/2020 and set strict: false.
Each AJV error has an instancePath (where in the manifest), a keyword (which rule failed), and a message. Group errors by instancePath for readable output — a single root cause inside a oneOf (like a layer) can fan out into many raw errors.
Common validation errors
The most frequent error. Almost every object in the schema sets additionalProperties: false (or unevaluatedProperties: false). Causes:
- A typo in a property name (
asetIdinstead ofassetId). - A property placed at the wrong level (e.g.
conditionon a panel instead of an edge). - Custom data without the
x-prefix. Only the manifest root, panels and extras blocks (the last two since 1.7) allowx-extension properties — see Extensions.
For a longer troubleshooting walkthrough see Validation Errors.
What schema validation does not catch
Schema validation is structural. These checks are up to application code (the CMS runs them as part of its own validation):
- Referential integrity — that every
assetId,characterId, edgefrom/to, andgraph.entrypoints to something that exists. - Graph reachability — that all panels are reachable from the entry.
- Cross-field constraints — e.g. for
loop-fromvideo playback,startAtMs <= loopFromMs < durationMsis documented in the schema but not structurally enforceable. - Asset availability — that variant
srcURLs actually resolve.
Validate early and often: on save in your authoring pipeline, in CI, and before publishing. A manifest that passes schema validation plus reference checks will load in the player without surprises.