Validation Code Reference
Every Preflight Validation issue code explained — what triggers it, whether it blocks publishing, and how to fix it in the PanelWave CMS.
Every issue that Preflight Validation reports carries a stable code (e.g. MISSING_ALT_TEXT). This page documents each code: what triggers it, its severity, and the recommended fix. The Learn more button on an issue in the CMS links directly to the matching section here. The Category column matches the groups in the preflight list — VARIANT_* issues are listed under Logic.
Errors block publishing; warnings and info items are advisory. See Validation & Preflight for how to run a validation, filter results, and apply auto-fixes.
All codes at a glance
Missing caption
Code: MISSING_CAPTION · Severity: Error · Category: Content
A speech bubble exists but has no text. Empty bubbles render as blank balloons in the player, so this blocks publishing.
How to fix: use Open in editor to jump to the panel, then either type the dialogue into the bubble or delete the bubble. See Speech Bubbles.
Broken link
Code: BROKEN_LINK · Severity: Error · Category: Integrity · Auto-fixable
A graph edge points at a panel that no longer exists — usually the panel was deleted after the edge was drawn. Readers following that path would hit a dead end.
How to fix: the Fix button removes the dangling edge. If the connection is still needed, prefer opening the Graph Editor and repointing the edge at the correct panel instead.
The auto-fix removes the reference — it cannot restore the missing target panel. If the panel was deleted by mistake, recreate it first.
Missing title
Code: MISSING_TITLE · Severity: Error · Category: Metadata
The work has no title in any locale. The title is required by the manifest format and is shown in libraries, previews, and social embeds.
How to fix: open Work Properties (gear icon in the editor header, or via Works) and enter a title for at least the default locale.
Oversized asset
Code: OVERSIZED_ASSET · Severity: Error (images) / Warning (audio, video) · Category: Performance
An asset exceeds its size budget:
| Asset type | Limit | Severity |
|---|---|---|
| Image | 5 MB | Error |
| Audio | 10 MB | Warning |
| Video | 50 MB | Warning |
Large files slow down loading for readers, especially on mobile networks — oversized images block publishing outright.
For images, the check judges the effective shipped size: when an optimized variant exists, its size is what counts, not the original upload's.
How to fix (images): click Optimize on the issue — or Optimize all (n) on the group — in preflight or in the publish wizard. The CMS re-encodes the image as WebP in the background (stepping down quality, then resolution, until it fits), keeps your full-quality original in the library, and ships the optimized variant in the published work. The issue clears automatically once the job finishes. See Auto-fixes.
How to fix (manual, or audio/video): re-export the source at a smaller resolution or higher compression (WebP/AVIF for images, AAC/Opus for audio, H.264/H.265 for video), then use Replace File on the asset in the Asset Library. The panel references stay intact. The issue's Used in links take you to each panel that displays the asset, so you can judge whether a smaller crop or a different asset is the better fix.
Video loop-from without mode
Code: VIDEO_LOOP_FROM_WITHOUT_MODE · Severity: Error · Category: Content
A video layer defines a loopFromMs timestamp, but its play mode is not loop-from. The timestamp only has meaning in loop-from mode (play once through, then loop from that point), so this combination is contradictory.
How to fix: in the layer's video settings either switch the play mode to loop-from, or clear the loop-from timestamp. See Video Panels.
Video loop-from before start
Code: VIDEO_LOOP_FROM_BEFORE_START · Severity: Error · Category: Content
A video layer's loop-from timestamp (loopFromMs) lies before its start offset (startAtMs). The loop would try to jump to a point that is never played.
How to fix: set the loop-from timestamp to a value at or after the start offset. See Video Panels.
Video loop-from beyond duration
Code: VIDEO_LOOP_FROM_BEYOND_DURATION · Severity: Error · Category: Content
A video layer's loop-from timestamp lies at or beyond the end of the video file, so the loop point can never be reached. (This check only runs once the video has been transcoded and its duration is known.)
How to fix: set the loop-from timestamp to a point inside the video — the issue's suggestion shows the video's actual duration in milliseconds.
Missing alt text
Code: MISSING_ALT_TEXT · Severity: Warning · Category: Accessibility
An image asset has no alternative text in any locale. Screen readers announce nothing useful for the image, and the work loses accessibility quality.
How to fix: either select the image layer in the editor and fill in the A11y inspector tab, or open the asset's Edit Metadata dialog in the Asset Library. Describe what the image shows, not that it is an image. Alt text is localizable — provide it per locale where the meaning differs. Use the issue's Used in links to jump to the panels where the image appears and see it in context.
Missing description
Code: MISSING_DESCRIPTION · Severity: Warning · Category: Metadata
The work has no description. Descriptions feed library listings, link previews, and SEO for published works.
How to fix: open Work Properties → Metadata and add a description (localizable).
Missing cover
Code: MISSING_COVER · Severity: Warning · Category: Metadata
The work has no cover image. Covers represent the work in libraries, embeds, and store-style listings.
How to fix: open Work Properties → Metadata and set a cover image.
Empty panel
Code: EMPTY_PANEL · Severity: Warning · Category: Content · Auto-fixable
A panel contains neither layers nor speech bubbles — readers would see a blank frame.
How to fix: add artwork or dialogue to the panel, or remove it. The Fix button deletes the empty panel (recent fixes can be undone from the validation page). Deleting it also removes the panel from the chapter's canvas layout, if it had a placement there.
Unknown text style ref
Code: UNKNOWN_TEXT_STYLE_REF · Severity: Warning · Category: Content
A text layer references a typography text style preset (styleRef) that is not defined in the work's settings. Rendering does not break — consumers ignore the unknown reference — but the intended styling is silently lost.
How to fix: text style presets come in with an imported manifest (the CMS has no editor for them yet; saving Work Properties keeps them). Re-import a manifest that defines the preset, or point the layer at an existing one. See Settings for how presets live in the manifest.
Animation unknown layer
Code: ANIMATION_UNKNOWN_LAYER · Severity: Warning · Category: Content
Keyframes of a panel's animation target a layer the panel no longer has — typically because the layer was deleted or replaced after the animation was built. The reader ignores such keyframes, so that part of the animation (or all of it) silently does not play. One warning per panel, with the number of affected keyframes.
How to fix: open the panel's animation in the Inspector. The affected keyframes are marked; re-create them on a current layer, or remove the animation.
Unknown balloon preset ref
Code: UNKNOWN_BALLOON_PRESET_REF · Severity: Warning · Category: Content
A speech bubble references a balloon preset (styleRef) that is not defined in the work's settings — same situation as an unknown text style, but for balloon styling.
How to fix: define the preset under Work Properties → Typography → Balloon Presets, or pick another one (or — None —) under Style preset in the bubble's Speech inspector, where the missing name shows as (missing). See Balloon presets.
Video hover start mode
Code: VIDEO_HOVER_START_MODE · Severity: Warning · Category: Content
A video layer starts on hover. Hover only exists in page view on devices with a pointer — in panel view and on touch devices the player falls back to on-click. The warning asks you to confirm that behavior is intended.
How to fix: if the work is read in page view with a mouse, this is fine — ignore the warning. Otherwise switch the layer's start mode to on-click (explicit) or on-view (autoplay, muted). See Video Panels and the video format reference.
Dangling page ref
Code: DANGLING_PAGE_REF · Severity: Warning · Category: Integrity · Auto-fixable
A page's reading order or layout still lists one or more panels that no longer exist. Deleting a panel cleans up its page references today, but pages edited before that clean-up existed can carry these leftovers — the editor's timeline then warns Panel not found, and the page's reading sequence contains a gap. The message names the page and chapter ("Page 3 of chapter 1 lists 2 panel(s) that no longer exist"). Panels are matched by their internal id and their friendly id, the same way the published manifest resolves them, so a panel that still exists is never reported. Older works can also list panels in a page's legacy panel list; the check finds deleted panels there too.
How to fix: click Fix. It removes the stale entries from that one page's reading order, layout and legacy panel list and nothing else; Undo restores the page exactly as it was. See Pages & Panels.
Canvas unknown panel
Code: CANVAS_UNKNOWN_PANEL · Severity: Error · Category: Integrity
A chapter's canvas layout has a placement for a panel that does not exist in the chapter. Deleting a panel removes its placement automatically, so this usually comes from older data or an import.
How to fix: remove the stale placement on the Canvas Layout board, or restore the panel.
Canvas no placements
Code: CANVAS_NO_PLACEMENTS · Severity: Error · Category: Integrity
The chapter has a canvas layout without a single panel placement — typically one that still holds decorations after its last panel was removed.
How to fix: place at least one panel on the Canvas Layout board, or remove the canvas layout.
Canvas unplaced panels
Code: CANVAS_UNPLACED_PANELS · Severity: Warning · Category: Content
Some panels of the chapter have no position on its canvas (the message lists up to five). Players lay out stray panels on their own, which rarely matches your intended composition.
How to fix: place the remaining panels on the Canvas Layout board.
Canvas too large
Code: CANVAS_TOO_LARGE · Severity: Warning · Category: Performance
The canvas has more than 150 placed panels — beyond the tested budget; very large canvases slow down low-end devices.
How to fix: consider splitting the chapter.
Canvas paywall revealed
Code: CANVAS_PAYWALL_REVEALED · Severity: Warning · Category: Content
Panels behind an active paywall rule are visible when readers zoom out over the canvas, because their reveal mode is not On visit — the overview would show paid artwork for free. A Chapter rule only counts for panels of its own chapter; Extras Item rules never gate panels and are ignored here.
How to fix: set those panels' reveal mode to On visit on the Canvas Layout board. See Reveal modes.
Paywall target missing
Code: PAYWALL_TARGET_MISSING · Severity: Error (active rule) / Warning (inactive rule) · Category: Integrity
A Chapter or Extras Item paywall rule has no target, targets a chapter or extras item that no longer exists, or targets an extras item that is still a draft. The message names the rule, for example Paywall rule "Chapter 3 premium" targets a chapter that no longer exists — it is left out of the published manifest, so that content would be free. An active rule like this blocks publishing, because the content it was meant to protect would ship without a paywall; an inactive one only warns.
How to fix: open Paywall, edit the rule and pick the chapter or extras item it gates (publish the extras item first if it is a draft), or delete the rule.
Canvas low resolution
Code: CANVAS_LOW_RESOLUTION · Severity: Warning · Category: Performance
Placed panels have artwork narrower than twice their width on the canvas. The camera zooms into panels, so on high-DPI screens this artwork looks soft.
How to fix: upload higher-resolution artwork, or make the placements smaller.
Variant no condition
Code: VARIANT_NO_CONDITION · Severity: Error · Category: Logic
A panel variant has no JSON Logic condition, so it can never apply and is skipped at publish.
How to fix: open the variant in the panel inspector and define its condition.
Variant duplicate id
Code: VARIANT_DUPLICATE_ID · Severity: Error · Category: Logic
Two variants of the same panel share an id.
How to fix: give each variant of the panel a unique id.
Variant unknown variable
Code: VARIANT_UNKNOWN_VARIABLE · Severity: Warning · Category: Logic
A variant's condition reads a variable that is neither defined in the Variables designer nor set by any hotspot action, so the condition can never become true as intended.
How to fix: define the variable, or correct the name in the condition — the variant editor's variable dropdown lists the defined ones.
Variant unknown override key
Code: VARIANT_UNKNOWN_OVERRIDE_KEY · Severity: Warning · Category: Logic
A variant overrides a field that variants are not allowed to change; that override is dropped from the published work.
How to fix: override only panel fields a variant may replace — title, description, duration, layers, speech bubbles, hotspots, and similar — as offered by the variant editor's Field list.
Variant empty overrides
Code: VARIANT_EMPTY_OVERRIDES · Severity: Warning · Category: Logic
The variant changes nothing publishable, so it is skipped at publish.
How to fix: add at least one override, or remove the variant.
Unreachable panels
Code: UNREACHABLE_PANELS · Severity: Warning · Category: Logic
Some panels of a chapter cannot be reached from its entry panel by following the connections in the graph, so readers paging through the work never see them. The message names the chapter and the count ("Chapter 1: 32 of 38 panel(s) cannot be reached from the entry panel…"), and the issue lists the affected panels by title. Typical cause: panels added after the chain was built, with no connection leading into them. Only chapters that have at least one connection are checked — a chapter read purely page by page, without a graph, is never reported.
How to fix: open the Graph Editor and connect the panels where they belong in the story — from the last reachable panel to the first unreachable one, or by inserting them into the chain. Delete panels that are leftovers.
Codes reserved for upcoming checks
Some categories shown in the validation UI (localization completeness, per-bubble audio, duplicate IDs) do not emit issues yet — their checks are planned but depend on data models still being built. Their codes will be documented here when they ship.