Linting & Warnings
Opt-in ZPL linting via the X-Linter and X-Warnings headers
The linter reports problems in your ZPL: unknown or unsupported commands, trimmed or invalid argument values, and render failures. It does not change how the label renders. It makes the renderer's silent defaults visible.
Turn on linting
Linting is off by default. Send the X-Linter: On request header on any
label-conversion request, as on Labelary:
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 an unlinted request and carries no X-Warnings header.
The X-Warnings response header
When linting is on and the renderer finds 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, with its prefix (e.g. ^FO, ^BC) — as in observed Labelary output |
paramNumber | 1-based argument number, empty when not argument-specific |
message | Human-readable description |
Pipes join multiple warnings. The header reports at most 20 warnings per request, and drops the rest silently, like Labelary.
The ^QQjunk above reports this, byte-identical to what live Labelary
returns for the same body:
X-Warnings: 22|3|^QQ||This ZPL command does not exist and was ignoredReported conditions
| Condition | Example message |
|---|---|
| Command name is not documented ZPL | This ZPL command does not exist and was ignored |
| Valid ZPL that the renderer does not implement | command "^PM" is valid ZPL but is not supported ... |
| Numeric argument has trailing garbage (the renderer trims it, as the ZPL specification requires) | Value '10abc' is not a valid number; suffix 'abc' was ignored |
| The renderer cannot interpret the argument value (uses the default) | 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 |
| The label requests a font that does not exist | Font 'Z' does not exist |
| Barcode or graphic fails to render | failed to render Code 128 barcode (^BC): ... |
The label references an image that no ~DG stored | ^XG references image "R:LOGO.GRF" which was never stored ... |
The linter does not warn about idiomatic omissions, such as trailing
arguments left off a command, as on Labelary. Where the renderer's fallback
differs from Labelary's, the message states what the renderer does. Labelary
replaces an out-of-range ^BQ magnification with its default. The renderer
clamps it to the nearest valid value, and says so.
Conditions never reported
111 of the 231 commands in the reference configure a printer instead of
drawing on a label: network settings, sensor calibration, print speed, host
status queries, RFID tag writes. The renderer ignores them and reports
IGNORED_COMMAND at info severity, which does not reach X-Warnings.
Labelary accepts the same commands silently.
A command that changes the label if the renderer implements it reports
UNSUPPORTED_COMMAND at warning severity, and reaches the header, as ^PM
does above. Labelary does not render those commands and reports nothing, so
these warnings are additional to Labelary's output.
The skip policy page lists which commands sit on which side.
Full diagnostics in the viewers
X-Warnings is flat text with a 20-entry limit, as on Labelary. For the full,
unlimited diagnostics, paste your ZPL into the online viewer
or the desktop app: severity levels (info / warning / error), stable
machine-readable codes (e.g. UNKNOWN_COMMAND, IGNORED_COMMAND,
ARGUMENT_TRIMMED), and precise source positions. Both show every diagnostic
next to the preview, and collapse repeated warnings to one line.
The Diagnostics Reference lists every diagnostic code, severity, and example.