Investigation notes · 23–24 October 2026
Investigating random gibberish from my HP 178nw
The same two-page print data produced gibberish with one opening chunk layout and printed correctly with another. This is how I got from an intermittent problem to a small workaround.
First, capture an actual failure
My HP Color Laser MFP 178nw would occasionally print random characters instead of the document. It happened from both a MacBook Pro and a MacBook Air. Retrying the same PDF could work. I wanted to see what was actually reaching the printer.
I enabled print logging and captured the IPP traffic from the Mac to the printer. A normal Preview print failed while the capture was running. The expected two pages didn’t print correctly. A photo of the output included something resembling the raster identifier among the characters, which was a clue worth checking.
I then used a small two-page PDF containing only numbered labels and three tiny colour squares. That also failed through Preview. It meant I could continue investigating with a document that used little toner and contained no personal information.
The PDF was 2,102 bytes. macOS converted it to a 24,138-byte Apple Raster stream, sent as image/urf. I reconstructed the TCP stream, decoded the HTTP chunks, extracted the raster and decoded its two pages offline. Both intended test pages were present in the transmitted data.
For this diagnostic transaction, the reconstructed request had no missing TCP sequence data or conflicting overlaps. The printer acknowledged the request and returned HTTP 200 / IPP successful-ok, despite producing gibberish. Protocol acceptance and job counters were not enough to tell me what had actually printed.
The interesting part: the first HTTP chunk containing raster data held just four bytes: UNIR. The rest of the identifier and opening structure came later.
Raster-data chunk lengths, in bytes:
[4, 16384, 7750]
Beginning of the first raster-data chunk:
55 4e 49 52 UNIRThese are the document-data chunks after the IPP attributes. They are not a list of all HTTP chunks or a list of TCP packet sizes.
Why 44 bytes?
The opening structure of this Apple Raster job consists of the file identifier, a page-count field and the first page’s header. Together, that is 44 bytes. It is not a 44-byte header repeated at the start of every page.
| Offset | Length | Contents |
|---|---|---|
| 0–7 | 8 bytes | UNIRAST\0 format identifier |
| 8–11 | 4 bytes | Page count: 00 00 00 02 (two pages) |
| 12–43 | 32 bytes | First page’s raster settings |
| 44 onward | Remaining stream | Compressed page data, followed by later page headers and data |
The original opening bytes were:
Identifier (8 bytes)
55 4e 49 52 41 53 54 00
Page count (4 bytes)
00 00 00 02
First-page header (32 bytes)
18 01 01 00 00 00 00 00
00 00 00 00 00 00 09 b0
00 00 0d b3 00 00 01 2c
00 00 00 00 00 00 00 00For this capture, the first-page settings describe 24 bits per pixel, sRGB, 2,480 × 3,507 pixels and 300 dpi. The field layout and Apple Raster read/write handling can be checked against the CUPS raster reader and writer.
I chose 44 because it includes the complete opening structure. I did not test every smaller buffer size, so I cannot claim that 44 is the minimum needed.
Replay the same data with different framing
I took the captured diagnostic raster and replayed it with different HTTP chunk boundaries. The document was byte-for-byte identical in all four comparisons. Its SHA-256 was:
90ab9f26cef47359aa874c58970353a4f8b0c966edd174997a865ec852b74ad4The decoded IPP bodies also matched after normalizing job-specific identifiers. The HTTP headers and job attributes were kept equivalent apart from the diagnostic title. I changed the opening layout, then varied the following chunk size to check whether that size explained the result.
| Printer job | Raster-data chunks (bytes) | Opening structure | Observed paper output |
|---|---|---|---|
| 1154 | [4, 16384, 7750] | Split after UNIR | Gibberish |
| 1155 | [44, 16344, 7750] | Complete in first chunk | Both numbered pages correct |
| 1156 | [44, 16384, 7710] | Complete in first chunk | Both numbered pages correct |
| 1157 | [4, 16344, 7790] | Split after UNIR | Gibberish |
Both complete-header variants succeeded. Both split-header variants failed. That held for both tested continuation sizes. I checked the physical pages rather than relying only on the printer’s completion status, and cancelled the failing jobs when they started producing extra output.
This is a useful controlled comparison, but a small one. Each matrix cell is one trial, and timing and printer state were not held perfectly constant. Earlier one-page split-header controls printed correctly. A four-byte first chunk alone is therefore not sufficient to make every job fail.
Put the workaround in the normal print path
The workaround is a small CUPS filter on a separate queue. It waits until it has collected the first 44 bytes, checks the UNIRAST\0 signature and writes those bytes together to its output pipe. It then streams the rest unchanged in blocks of up to 64 KiB.
Read until 44 bytes are available
Validate the Apple Raster signature
Write the 44-byte opening structure together
Stream the remaining bytes unchangedI printed the same two-page test PDF from Preview through that queue. Both numbered pages printed correctly. The resulting raster was again the same 24,138 bytes with the same SHA-256.
The successful Preview job’s document-data HTTP chunks were [16384, 7754]. The first chunk now contained the complete opening structure. It did not need to be exactly 44 bytes long.
A pipe write is not a TCP packet. The filter does not control the printer’s reads or guarantee network packet boundaries. The macOS backend can combine the opening write with later data, as this successful capture shows. TCP does not preserve application write boundaries; see RFC 9293, section 3.7.
The filter buffers only the beginning, so a larger document doesn’t require a larger opening buffer. Offline checks verified exact byte preservation on captured rasters of 7,107, 24,138 and 1,724,311 bytes, along with fragmented input, invalid or incomplete openings, cancellation and file-input mode. The public source also includes synthetic offline tests.
The menu-bar app packages this into an installer, On/Off selection of the buffered queue, optional Launch at login and a removal utility. CUPS runs the filter for jobs sent to that queue, including while the app is closed.
What I think is happening, and what I haven’t proved
The results point to a reception or interpretation problem triggered by the initial delivery of the raster data. The printer appears to mishandle some jobs when it receives only part of the opening structure first.
I cannot inspect HP’s proprietary firmware. I have not isolated whether the underlying defect is in HTTP chunk handling, TCP read buffering, print-language detection or an interaction between them. The filter changes delivery timing and grouping; these tests do not identify a particular firmware function.
I have not measured a long-term failure rate, established a minimum buffer size or validated other HP models. The small matrix is not a guarantee for every document or network. This is also not a printer firmware update.
What I could verify was narrower: the same raster failed in both split-header matrix cases, succeeded in both complete-header cases, and then printed correctly through Preview with the filter installed.
Test data and source
The files below contain the non-personal diagnostic material used for the comparison. The results JSON includes the opening bytes, chunk layouts, document hash, physical outcomes and limitations. The captured raster contains only the two numbered test pages and three tiny colour squares on each page.
- Structured test results and opening bytes (JSON)
- Captured diagnostic raster (24,138 bytes)
- Original two-page print-test PDF (uses little toner)
- App, filter and offline test source (MIT)
The downloadable source builds the app and runs offline checks. It does not automatically replay these physical printer tests. Repeating a failing variant can waste paper and toner.
The raw traffic captures, private documents, printer addresses and local machine details are not published. This write-up contains the relevant structure and results from the diagnostic jobs.
Download the app · Read the responsibility notice · Return to the project page