OverviewValidation

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.

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:

OptionDefaultDescription
-s, --schema <version>1.0.0Schema version to validate against (resolved by major version to the bundled schema/<major>.0/panelwave.schema.json)
--strictoffAlso fail (exit code 1) when there are warnings
--jsonoffMachine-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 assets section — panels referencing assetIds will fail at runtime.
  • No characters in meta — speech bubbles with a characterId will 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 (asetId instead of assetId).
  • A property placed at the wrong level (e.g. condition on 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) allow x- 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, edge from/to, and graph.entry points to something that exists.
  • Graph reachability — that all panels are reachable from the entry.
  • Cross-field constraints — e.g. for loop-from video playback, startAtMs <= loopFromMs < durationMs is documented in the schema but not structurally enforceable.
  • Asset availability — that variant src URLs 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.