ocrmypdf/OCRmyPDF · warning
PDF graphics stack underflowed - PDF may be malformed
Error message
PDF graphics stack underflowed - PDF may be malformed
What it means
A 'Q' (restore graphics state) operator was encountered with an empty state stack — the PDF is unbalanced/malformed. The interpreter keeps the current state and warns; downstream ink analysis may be slightly off but processing continues.
Source
Thrown at src/ocrmypdf/pdfinfo/_contentstream.py:199
for n, graphobj in enumerate(
_normalize_stack(parse_content_stream(contentstream, operator_whitelist))
):
operands, operator = graphobj
if operator == 'q':
stack.append((ctm, fill_ink, fill_space))
if len(stack) > 32: # See docstring
if len(stack) > 128:
raise RuntimeError(
f"PDF graphics stack overflowed hard limit at operator {n}"
)
warn("PDF graphics stack overflowed spec limit")
elif operator == 'Q':
try:
ctm, fill_ink, fill_space = stack.pop()
except IndexError:
# Keeping the state the same seems to be the only sensible thing
# to do. Just pretend nothing happened, keep calm and carry on.
warn("PDF graphics stack underflowed - PDF may be malformed")
elif operator == 'cm':
try:
ctm = Matrix(operands) @ ctm
except ValueError as e:
raise InputFileError(
"PDF content stream is corrupt - this PDF is malformed. "
"Use a PDF editor that is capable of visually inspecting the PDF."
) from e
elif operator == 'g':
if vals := _operand_floats(operands):
fill_ink = _ink_from_components('gray', vals)
fill_space = '/DeviceGray'
elif operator == 'rg':
if vals := _operand_floats(operands):
fill_ink = _ink_from_components('rgb', vals)
fill_space = '/DeviceRGB'
elif operator == 'k':
if vals := _operand_floats(operands):View on GitHub (pinned to 5074a0b0e1)
Solutions
- No action needed unless ink-based preprocessing decisions look wrong
- Repair/normalize the PDF with qpdf or pikepdf to rebalance the content stream
- If you generate PDFs yourself, ensure every q has a matching Q
Example fix
# before # process original.pdf directly (warning printed) // after qpdf --object-streams=disable original.pdf fixed.pdf # then process fixed.pdf
Defensive patterns
Strategy: fallback
Try / catch
with warnings.catch_warnings():\n warnings.simplefilter('ignore', UserWarning, message='PDF graphics stack underflowed')\n process(path) Prevention
- Repair unbalanced content streams with qpdf before processing
- If you generate PDFs, match every q with a Q
- Treat warnings as diagnostics, not failures — output remains usable
When it happens
Trigger: Interpreting a content stream where Q operators outnumber q operators — hand-edited or broken PDF content streams.
Common situations: PDFs from buggy generators, hand-crafted content streams, or files that survived partial corruption; usually harmless to output quality.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- PDF graphics stack overflowed spec limit
- This PDF contains dynamic XFA forms created by Adobe LiveCyc
- pdfminer could not process page {pageno} (counting from 0).
- pdfminer did not find page {pageno} in the input file.
AI-assisted analysis of ocrmypdf/OCRmyPDF@5074a0b0e1 (2026-08-27).
Data as JSON: /api/errors/2ccfda5dfee9c0a9.
Report an issue: GitHub.