Stripy Horse
Stripy Horse

← All guides

Zebra printer prints the ZPL code as text instead of the label

You send this:

^XA^FO50,50^A0N,45,45^FDHello^FS^XZ

and the printer feeds a label with ^XA^FO50,50^A0N,45,45^FDHello^FS^XZ printed across it in small type. Sometimes it wraps across several labels.

Your ZPL is fine. The printer received it, understood it as characters, and did exactly what it was told. Something upstream told it to treat the stream as text rather than as a format to run.

There are three causes, and you can tell them apart in about a minute.

Cause 1: the printer is in diagnostic (dump) mode

This is the common one, and it is sticky: ~JD puts a Zebra into diagnostic mode, where it prints every byte it receives instead of interpreting it, and it stays there across power cycles until something sends ~JE. People arrive here after following a troubleshooting post, or from a colleague who left it on months ago.

Ask the printer

~HS returns three lines of status. Send it and read the seventh field of the first line, which is the diagnostic-mode flag:

(printf '~HS'; sleep 2) | nc 192.168.1.157 9100

Real output from a GX430t:

030,0,0,1824,002,0,0,0,000,0,0,0
001,0,0,0,1,2,6,0,00000000,1,000
1234,0

Counting the first line: 030 0 0 1824 002 0 0 0 000 0 0 0. That seventh field is 0, so this printer is not in diagnostic mode. A 1 there is your answer, and you can stop reading.

While you are looking, the fourth field (1824) is the label length in dots, which is useful for a different problem: at 12 dpmm that is 152 mm, a correct 6-inch label.

Fix

printf '~JE' | nc 192.168.1.157 9100

That is the whole fix. Print again.

Cause 2: the printer is not listening for ZPL

Zebra printers can speak more than one language, and the desktop models ship speaking EPL as well as ZPL. If the active language does not include ZPL, your ^XA is just characters.

Ask over SGD:

(printf '! U1 getvar "device.languages"\r\n'; sleep 1) | nc 192.168.1.157 9100

Real answer from the same printer:

"epl_zpl"

epl_zpl is the safe setting: the printer auto-detects per job, so both work. The values that cause this symptom are epl and line_print. To set it:

printf '! U1 setvar "device.languages" "zpl"\r\n' | nc 192.168.1.157 9100

Use epl_zpl rather than zpl if anything else on your network still sends EPL.

Cause 3: something is sending it as a document

If the printer is healthy, the problem is on your side, and it is almost always that the ZPL went through a printer driver instead of straight to the printer. A driver's job is to render a document into the printer's language, so handing it a file that is already ZPL means it renders the text of your ZPL into ZPL. It does its job perfectly and you get the code on paper.

Symptoms that point here: it prints in a nice proportional font, or with margins, or you printed by opening the file and pressing Ctrl-P.

ZPL must be sent raw. Not through Word, Notepad, a print dialog, or a Windows driver queue:

# macOS / Linux cat label.zpl | nc 192.168.1.157 9100

If you must go through a Windows queue, install the printer as a Generic / Text Only driver on a Standard TCP/IP RAW port at 9100, which passes bytes through untouched. The Zebra-branded driver will not.

Still printing text after all three?

Then check the ZPL itself before blaming the printer. A stream that never opens with ^XA or never closes with ^XZ is not a format, and some firmware will echo it. Paste it into the ZPL viewer: if it renders a label there, the ZPL is valid and the problem is one of the three above.

You can also take the printer out of the question entirely. Point your app at a virtual Zebra printer, which speaks raw TCP 9100 like the real thing and shows you what arrived. If the label appears there and text appears on your desk, the difference is the printer's configuration, not your code.

Why does it come back after a power cycle?

Diagnostic mode is stored in the printer, not in the session. ~JD survives reboots; only ~JE clears it. If the symptom returned after someone power-cycled "to fix it", this is why.

The label prints the code and then a blank label

Normal in diagnostic mode: it dumps what it received, then feeds. It is not a second fault.

Does this affect the ~ and ^ characters specifically?

Both are the ZPL control prefixes, so if either has been remapped (~CC or ^CC changes them) the printer stops recognising your commands and treats them as data. Rare, but it is the same class of problem, and ~JE will not fix it. Reset the prefix or factory-default the printer.

Stripy Horse is the developer platform for Zebra printing: convert PDFs and images, design labels in HTML, preview ZPL pixel-true, and test against virtual printers in CI. Get in touch or try the free tools.

Published 2026-09-03 · Ben Faerber, software engineer, five years building warehouse fulfillment and label-printing systems; maintainer of pdf-to-zpl (27,000+ installs powering production label generation).