zpl.tools
Compatibility LayersLabelary Compatibility

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}
FieldMeaning
byteIndexByte offset of the offending span in the submitted ZPL — the argument itself when the warning is argument-specific, otherwise the command
byteSizeLength in bytes of that span
commandNameCommand name as written, including its prefix (e.g. ^FO, ^BC) — matching observed Labelary output
paramNumber1-based argument number, empty when not argument-specific
messageHuman-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 ignored

What gets reported

ConditionExample message
Command name is not documented ZPLThis ZPL command does not exist and was ignored
Command is valid ZPL but not implemented by the renderercommand "^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 requestedFont 'Z' does not exist
Barcode or graphic failed to renderfailed 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.