Linting & Warnings
Opt-in ZPL linting via the X-Linter and X-Warnings headers
The compatibility layer can report problems it found in your ZPL — unknown or unsupported commands, trimmed or invalid argument values, and rendering failures — without changing how the label renders. Rendering is always best-effort, exactly like a physical Zebra printer; linting only makes the silent fallbacks visible.
Enabling linting
Linting is off by default. Send the X-Linter: On request header (matching
Labelary's behavior) on any label-conversion request:
curl --request POST 'https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6/0' \
--header 'X-API-Key: YOUR_API_KEY' \
--header 'X-Linter: On' \
--header 'Accept: image/png' \
--data '^XA^FO50,50^FDHello^FS^QQjunk^XZ'Without the header (or with X-Linter: Off) the response is byte-identical
to a non-linted request and no X-Warnings header is present.
The X-Warnings response header
When linting is on and the engine found problems, the response carries an
X-Warnings header. Each warning is five pipe-delimited fields:
{byteIndex}|{byteSize}|{commandName}|{paramNumber}|{message}| Field | Meaning |
|---|---|
byteIndex | Byte offset of the offending span in the submitted ZPL — the argument itself when the warning is argument-specific, otherwise the command |
byteSize | Length in bytes of that span |
commandName | Command name as written, including its prefix (e.g. ^FO, ^BC) — matching observed Labelary output |
paramNumber | 1-based argument number, empty when not argument-specific |
message | Human-readable description |
Multiple warnings are joined with pipes. At most 20 warnings are reported per request; anything beyond that is dropped silently (matching Labelary's cap).
Example — the ^QQjunk above produces (byte-identical to what live
Labelary returns for the same body):
X-Warnings: 22|3|^QQ||This ZPL command does not exist and was ignoredWhat gets reported
| Condition | Example message |
|---|---|
| Command name is not documented ZPL | This ZPL command does not exist and was ignored |
| Command is valid ZPL but not implemented by the renderer | command "^KL" is valid ZPL but is not supported ... |
| Numeric argument had trailing garbage (trimmed per ZPL spec) | Value '10abc' is not a valid number; suffix 'abc' was ignored |
| Argument value could not be interpreted (fallback used) | Value 'ab' is not a valid number and was ignored |
| Argument value outside its valid range (clamped) | Value 5 is less than minimum value 10; used 10 instead |
| Argument value outside its valid range (kept as written) | Value 0 is less than minimum value 1 and was used as written |
| A font that does not exist was requested | Font 'Z' does not exist |
| Barcode or graphic failed to render | failed to render Code 128 barcode (^BC): ... |
| A stored image is referenced but was never downloaded | ^XG references image "R:LOGO.GRF" which was never stored ... |
Idiomatic omissions — leaving trailing arguments off a command so defaults
apply — are not warned about (matching Labelary). Where our engine's
fallback differs from Labelary's, the message says what this engine
did — e.g. Labelary replaces an out-of-range ^BQ magnification with its
default and says so, while this renderer clamps it to the nearest valid
value and says that. Warnings for commands Labelary silently accepts
(documented-but-unimplemented commands like ^KL) are additional here by
design.
Full diagnostics in the viewers
X-Warnings is how the API delivers diagnostics: the warnings arrive on
the same response as the rendered label, so you never render twice. The
header format is intentionally constrained (flat text, 20-entry cap,
matching Labelary).
For the full, uncapped diagnostics — severity levels
(info / warning / error), stable machine-readable codes (e.g.
UNKNOWN_COMMAND, ARGUMENT_TRIMMED), and precise source positions —
paste your ZPL into the online viewer or the desktop
app. Both show every diagnostic inline next to the preview, grouped so
repeated warnings across a multi-label file read as one line.
The complete list of diagnostic codes, severities, and examples lives in the Diagnostics Reference.