Summary
cfFilterGhostscript() formats PWG/Apple Raster duplex transform fields with %u. For printers that advertise URF duplex mode DM3 (Rotated), raster_base_header() stores CrossFeedTransform/FeedTransform as -1 in the unsigned cupsInteger[1] / cupsInteger[2] slots. That becomes 4294967295 on the Ghostscript command line. Ghostscript's appleraster device reads those parameters with param_read_int() (signed 32-bit), so the job dies with:
ERROR: Error setting cupsInteger1 ...
Unrecoverable error: rangecheck in .putdeviceprops
CUPS then pauses the queue (Job processing failed.). Simplex jobs work. Duplex PDF → URF jobs fail every time.
This is not a cups-browsed or CUPS daemon bug. Driverless IPP just happens to take this path because the printer does not accept PDF.
Environment
- Arch Linux (Omarchy 4.0.1), aarch64
- libcupsfilters 2.2.1-2
- cups-filters 2.0.1-2
- cups-browsed 2.1.1-1
- CUPS 2.4.19
- Ghostscript 10.07.1
- Printer: EPSON ET-16650 Series (driverless IPP / Apple Raster)
urf-supported includes DM3 (Rotated duplex)
Printer document formats: image/pwg-raster, image/urf, image/jpeg, application/vnd.epson.escpr (no PDF).
How to reproduce
- Use a driverless IPP queue whose printer advertises URF duplex mode DM3.
- Print a PDF with duplex long-edge (
Duplex=DuplexNoTumble / sides=two-sided-long-edge).
- Filter chain:
pdftopdf → cfFilterGhostscript (-sDEVICE=appleraster) → IPP backend.
CUPS log from a real job:
FINAL_CONTENT_TYPE=image/urf
argv[5]: ... Duplex=DuplexNoTumble ... InputSlot=Main ... PageSize=Letter ...
cfFilterGhostscript: Ghostscript command line: gs ... -sDEVICE=appleraster ... -dDuplex ...
-dcupsInteger1=4294967295 -dcupsInteger2=4294967295 -dcupsInteger8=4
-scupsPageSizeName=Letter -scupsBackSideOrientation=Rotated ...
cfFilterGhostscript: Error setting cupsInteger1 ...
cfFilterGhostscript: Unrecoverable error: rangecheck in .putdeviceprops
Job processing failed.
cupsfilter with only a PPD does not reproduce this: that path never loads printer IPP attributes, so it never applies the DM3 transforms.
It does reproduce with libcupsfilters against the live printer:
data.printer_attrs = cfGetPrinterAttributes("ipp://printer/ipp/print", NULL, 0, NULL, 0, 0);
data.num_options = cupsAddOption("Duplex", "DuplexNoTumble", ...);
cfRasterPrepareHeader(&h, &data, CF_FILTER_OUT_FORMAT_APPLE_RASTER, ...);
/* h.cupsInteger[1] == 4294967295u, (int)h.cupsInteger[1] == -1 */
cfFilterGhostscript(...); /* fails with the Ghostscript line above */
On this Epson that printed:
urf-supported: ... DM3 ...
Duplex=1 Tumble=0
cupsInteger[1] unsigned=4294967295 signed=-1
cupsInteger[2] unsigned=4294967295 signed=-1
cfFilterGhostscript status=1
Isolated Ghostscript confirmation (no printer required)
# Fails (what libcupsfilters currently emits)
gs -dQUIET -dSAFER -dNOPAUSE -dBATCH -sDEVICE=appleraster \
-sOutputFile=/dev/null -r600x600 \
-dDEVICEWIDTHPOINTS=612 -dDEVICEHEIGHTPOINTS=792 \
-dcupsInteger1=4294967295 -dcupsInteger2=4294967295 \
-c quit
# ERROR: Error setting cupsInteger1 ...
# Unrecoverable error: rangecheck in .putdeviceprops
# Succeeds (the intended PWG transform values)
gs -dQUIET -dSAFER -dNOPAUSE -dBATCH -sDEVICE=appleraster \
-sOutputFile=/dev/null -r600x600 \
-dDEVICEWIDTHPOINTS=612 -dDEVICEHEIGHTPOINTS=792 \
-dcupsInteger1=-1 -dcupsInteger2=-1 \
-c quit
# INFO: Rendering completed
The full cfFilterGhostscript command line behaves the same way: 4294967295 → exit 255 and empty output; -1 → 76 KB Apple Raster from a 2-page PDF.
Root cause
In cupsfilters/raster.c (raster_base_header()), PWG/Apple Raster duplex with Rotated / DM3 and long-edge (Tumble == CUPS_FALSE) does:
h->cupsInteger[1] = -1; /* CrossFeedTransform */
h->cupsInteger[2] = -1; /* FeedTransform */
cupsInteger[] is unsigned, so those become UINT32_MAX. That is the usual two's-complement encoding of -1 in a PWG Raster header and is correct inside the raster header.
In cupsfilters/ghostscript.c (header_to_gs_args()):
for (i = 0; i <= 15; i ++)
if (h->cupsInteger[i])
{
snprintf(tmpstr, sizeof(tmpstr), "-dcupsInteger%d=%u",
i, (unsigned)(h->cupsInteger[i]));
cupsArrayAdd(gs_args, strdup(tmpstr));
}
UINT32_MAX is non-zero, so it is passed as -dcupsInteger1=4294967295. Ghostscript cups/gdevcups.c uses param_read_int() for cupsIntegerN, which cannot hold that value.
cupsInteger8=4 in the failing command is print-quality (normal) and is fine.
Suggested fix
Format the Ghostscript integers as signed, which turns the stored UINT32_MAX back into -1:
snprintf(tmpstr, sizeof(tmpstr), "-dcupsInteger%d=%d",
i, (int)h->cupsInteger[i]);
That matches how these fields are used as PWG CrossFeed/Feed transforms (±1). Passing -dcupsInteger1=-1 was verified to make Ghostscript 10.07.1 accept the device setup and rasterize the PDF.
Expected
Duplex driverless PDF → Apple/PWG Raster jobs complete. CUPS should not pause the printer.
Actual
Ghostscript aborts during device setup. The job fails and CUPS stops the queue until it is re-enabled.
Disclosure: Debugged, documented, and drafted by Grok (xAI). The failure was reproduced on this machine against libcupsfilters 2.2.1 and Ghostscript 10.07.1; the suggested %d / (int) change was checked with the same Ghostscript command line ( 4294967295 fails, -1 rasterizes). A human is submitting the report.
Summary
cfFilterGhostscript()formats PWG/Apple Raster duplex transform fields with%u. For printers that advertise URF duplex mode DM3 (Rotated),raster_base_header()stores CrossFeedTransform/FeedTransform as-1in the unsignedcupsInteger[1]/cupsInteger[2]slots. That becomes4294967295on the Ghostscript command line. Ghostscript'sapplerasterdevice reads those parameters withparam_read_int()(signed 32-bit), so the job dies with:CUPS then pauses the queue (
Job processing failed.). Simplex jobs work. Duplex PDF → URF jobs fail every time.This is not a cups-browsed or CUPS daemon bug. Driverless IPP just happens to take this path because the printer does not accept PDF.
Environment
urf-supportedincludesDM3(Rotated duplex)Printer document formats:
image/pwg-raster,image/urf,image/jpeg,application/vnd.epson.escpr(no PDF).How to reproduce
Duplex=DuplexNoTumble/sides=two-sided-long-edge).pdftopdf→cfFilterGhostscript(-sDEVICE=appleraster) → IPP backend.CUPS log from a real job:
cupsfilterwith only a PPD does not reproduce this: that path never loads printer IPP attributes, so it never applies the DM3 transforms.It does reproduce with libcupsfilters against the live printer:
On this Epson that printed:
Isolated Ghostscript confirmation (no printer required)
The full
cfFilterGhostscriptcommand line behaves the same way:4294967295→ exit 255 and empty output;-1→ 76 KB Apple Raster from a 2-page PDF.Root cause
In
cupsfilters/raster.c(raster_base_header()), PWG/Apple Raster duplex with Rotated / DM3 and long-edge (Tumble == CUPS_FALSE) does:cupsInteger[]isunsigned, so those becomeUINT32_MAX. That is the usual two's-complement encoding of -1 in a PWG Raster header and is correct inside the raster header.In
cupsfilters/ghostscript.c(header_to_gs_args()):UINT32_MAXis non-zero, so it is passed as-dcupsInteger1=4294967295. Ghostscriptcups/gdevcups.cusesparam_read_int()forcupsIntegerN, which cannot hold that value.cupsInteger8=4in the failing command is print-quality (normal) and is fine.Suggested fix
Format the Ghostscript integers as signed, which turns the stored
UINT32_MAXback into-1:That matches how these fields are used as PWG CrossFeed/Feed transforms (±1). Passing
-dcupsInteger1=-1was verified to make Ghostscript 10.07.1 accept the device setup and rasterize the PDF.Expected
Duplex driverless PDF → Apple/PWG Raster jobs complete. CUPS should not pause the printer.
Actual
Ghostscript aborts during device setup. The job fails and CUPS stops the queue until it is re-enabled.
Disclosure: Debugged, documented, and drafted by Grok (xAI). The failure was reproduced on this machine against libcupsfilters 2.2.1 and Ghostscript 10.07.1; the suggested
%d/(int)change was checked with the same Ghostscript command line (4294967295fails,-1rasterizes). A human is submitting the report.