{"record":{"id":"2ccfda5dfee9c0a9","repo":"ocrmypdf/OCRmyPDF","slug":"pdf-graphics-stack-underflowed-pdf-may-be-malfor","errorCode":null,"errorMessage":"PDF graphics stack underflowed - PDF may be malformed","messagePattern":"PDF graphics stack underflowed - PDF may be malformed","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/ocrmypdf/pdfinfo/_contentstream.py","lineNumber":199,"sourceCode":"    for n, graphobj in enumerate(\n        _normalize_stack(parse_content_stream(contentstream, operator_whitelist))\n    ):\n        operands, operator = graphobj\n        if operator == 'q':\n            stack.append((ctm, fill_ink, fill_space))\n            if len(stack) > 32:  # See docstring\n                if len(stack) > 128:\n                    raise RuntimeError(\n                        f\"PDF graphics stack overflowed hard limit at operator {n}\"\n                    )\n                warn(\"PDF graphics stack overflowed spec limit\")\n        elif operator == 'Q':\n            try:\n                ctm, fill_ink, fill_space = stack.pop()\n            except IndexError:\n                # Keeping the state the same seems to be the only sensible thing\n                # to do. Just pretend nothing happened, keep calm and carry on.\n                warn(\"PDF graphics stack underflowed - PDF may be malformed\")\n        elif operator == 'cm':\n            try:\n                ctm = Matrix(operands) @ ctm\n            except ValueError as e:\n                raise InputFileError(\n                    \"PDF content stream is corrupt - this PDF is malformed. \"\n                    \"Use a PDF editor that is capable of visually inspecting the PDF.\"\n                ) from e\n        elif operator == 'g':\n            if vals := _operand_floats(operands):\n                fill_ink = _ink_from_components('gray', vals)\n                fill_space = '/DeviceGray'\n        elif operator == 'rg':\n            if vals := _operand_floats(operands):\n                fill_ink = _ink_from_components('rgb', vals)\n                fill_space = '/DeviceRGB'\n        elif operator == 'k':\n            if vals := _operand_floats(operands):","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/ocrmypdf/OCRmyPDF/blob/5074a0b0e109362422b768fd271ed84bf717c4ec/src/ocrmypdf/pdfinfo/_contentstream.py#L181-L217","documentation":"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.","triggerScenarios":"Interpreting a content stream where Q operators outnumber q operators — hand-edited or broken PDF content streams.","commonSituations":"PDFs from buggy generators, hand-crafted content streams, or files that survived partial corruption; usually harmless to output quality.","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"],"exampleFix":"# before\n# process original.pdf directly (warning printed)\n// after\nqpdf --object-streams=disable original.pdf fixed.pdf  # then process fixed.pdf","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"with warnings.catch_warnings():\\n    warnings.simplefilter('ignore', UserWarning, message='PDF graphics stack underflowed')\\n    process(path)","preventionTips":["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"],"tags":["pdf","content-stream","graphics-state","malformed-pdf"],"backgroundTag":"pdf-graphics-stack-underflow","analyzedSha":"5074a0b0e109362422b768fd271ed84bf717c4ec","analyzedAt":"2026-08-27T11:57:38.523Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}