{"record":{"id":"882cbbab22f86142","repo":"opendataloader-project/opendataloader-pdf","slug":"is-encrypted-tagged-pdf-conversion-is-not-su","errorCode":null,"errorMessage":"'{}' is encrypted; tagged-pdf conversion is not supported for encrypted documents.","messagePattern":"'(.+?)' is encrypted; tagged-pdf conversion is not supported for encrypted documents\\.","errorType":"exception","errorClass":"EncryptedTaggedPdfNotSupportedException","httpStatus":null,"severity":"error","filePath":"java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/processors/AutoTaggingProcessor.java","lineNumber":110,"sourceCode":"        COSDocument cosDocument = document.getDocument();\n        PDCatalog catalog = document.getCatalog();\n        COSObject structTreeRoot = createStructTreeRoot(catalog, cosDocument, document);\n        createStructureTreeElements(document, contents, structTreeRoot, cosDocument);\n        if (isPDF2_0) {\n            updateDestinationsToStructureDestinations(document, catalog, cosDocument);\n        }\n        updatePages(document, cosDocument);\n        createParentTree(cosDocument, structTreeRoot);\n        cosDocument.getTrailer().removeKey(ASAtom.ENCRYPT);\n    }\n\n    /**\n     * Tag a PDF document and save to disk. Existing behavior preserved.\n     */\n    public static synchronized void createTaggedPDF(File inputPDF, String outputFolder, PDDocument document, List<List<IObject>> contents) throws IOException {\n        COSObject encrypt = document.getDocument().getTrailer().getEncrypt();\n        if (encrypt != null && !encrypt.empty()) {\n            throw new EncryptedTaggedPdfNotSupportedException(\n                \"'\" + inputPDF.getName() + \"' is encrypted; tagged-pdf conversion is not supported for encrypted documents.\");\n        }\n        tagDocument(document, contents, null);\n        String outputFileName = outputFolder + File.separator +\n                FileUtils.getBaseName(inputPDF.getName()) + \"_tagged.pdf\";\n        document.saveAs(outputFileName);\n        LOGGER.log(Level.INFO, \"Created {0}\", outputFileName);\n    }\n\n    private static void updatePages(PDDocument document, COSDocument cosDocument) throws IOException {\n        for (OperatorStreamKey operatorStreamKey : structParents.keySet()) {\n            structParentsIntegers.put(operatorStreamKey, currentStructParent++);\n        }\n        List<PDPage> rawPages = document.getPages();\n        for (int pageNumber = 0; pageNumber < rawPages.size(); pageNumber++) {\n            PDPage page = rawPages.get(pageNumber);\n            if (isPDF2_0) {\n                updateAdditionalAction(page.getObject(), cosDocument, document);","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/processors/AutoTaggingProcessor.java#L92-L128","documentation":"AutoTaggingProcessor.createTaggedPDF() checks the PDF document's trailer dictionary for an Encrypt entry before attempting to add accessibility tags. Encrypted PDFs cannot be tagged because the structure tree modifications would require decrypting and re-encrypting content streams, which this library does not support. The custom EncryptedTaggedPdfNotSupportedException exception makes the failure mode explicit and distinguishable from generic IOExceptions.","triggerScenarios":"Calling AutoTaggingProcessor.createTaggedPDF(inputPDF, outputFolder, document, contents) where the PDDocument was loaded from a PDF whose trailer dictionary contains a non-empty Encrypt COS object. The check is `document.getDocument().getTrailer().getEncrypt()` returning a non-null, non-empty COSObject. This happens with both owner-password and user-password encrypted PDFs.","commonSituations":"Processing a batch of PDFs where some are password-protected (even with an empty user password); tagged-pdf output format requested (--format tagged-pdf) on a document that has DRM or permissions encryption; a PDF signed with digital signatures that include encryption; scanned documents from a copier that applies encryption by default.","solutions":["Decrypt the PDF before processing: load it with the password via PDDocument.load(file, password), then save it unencrypted with document.setAllSecurityToBeRemoved(true) before calling createTaggedPDF.","Skip encrypted documents in batch processing by catching EncryptedTaggedPdfNotSupportedException and logging a warning.","Use a tool like qpdf to remove encryption: `qpdf --decrypt input.pdf output.pdf`."],"exampleFix":"// before: encrypted PDF throws and stops the batch\nAutoTaggingProcessor.createTaggedPDF(inputPDF, outputFolder, document, contents);\n\n// after: decrypt before tagging, or skip gracefully\nCOSObject encrypt = document.getDocument().getTrailer().getEncrypt();\nif (encrypt != null && !encrypt.empty()) {\n    // Option A: decrypt if password is known\n    document.setAllSecurityToBeRemoved(true);\n    // Option B: skip encrypted documents\n    // LOGGER.warning(\"Skipping encrypted PDF: \" + inputPDF.getName());\n    // continue;\n}\nAutoTaggingProcessor.createTaggedPDF(inputPDF, outputFolder, document, contents);","handlingStrategy":"try-catch","validationCode":"// Check for encryption before calling createTaggedPDF\nCOSObject encrypt = document.getDocument().getTrailer().getEncrypt();\nboolean isEncrypted = encrypt != null && !encrypt.empty();\nif (isEncrypted) {\n    // Decrypt if password is known, or skip\n    document.setAllSecurityToBeRemoved(true);\n    // Re-save to apply decryption\n    File tempFile = File.createTempFile(\"decrypted\", \".pdf\");\n    document.save(tempFile);\n    document = PDDocument.load(tempFile);\n}","typeGuard":"public static boolean isEncrypted(PDDocument document) {\n    COSObject encrypt = document.getDocument().getTrailer().getEncrypt();\n    return encrypt != null && !encrypt.empty();\n}","tryCatchPattern":"try {\n    AutoTaggingProcessor.createTaggedPDF(inputPDF, outputFolder, document, contents);\n} catch (EncryptedTaggedPdfNotSupportedException e) {\n    // Option A: decrypt and retry if password is known\n    document.setAllSecurityToBeRemoved(true);\n    File temp = File.createTempFile(\"decrypted-\", \".pdf\");\n    document.save(temp);\n    try (PDDocument decrypted = PDDocument.load(temp)) {\n        AutoTaggingProcessor.createTaggedPDF(inputPDF, outputFolder, decrypted, contents);\n    }\n    // Option B: skip encrypted documents in batch processing\n    // LOGGER.warning(\"Skipping encrypted PDF: \" + inputPDF.getName());\n}","preventionTips":["Check isEncrypted(document) before calling createTaggedPDF in batch processing.","Pre-decrypt PDFs with qpdf --decrypt in a preprocessing step.","Catch EncryptedTaggedPdfNotSupportedException specifically — it extends a custom exception, not IOException.","Load encrypted PDFs with the password: PDDocument.load(file, password) then setAllSecurityToBeRemoved(true).","Filter encrypted PDFs out of tagged-pdf output format requests at the CLI/batch level."],"tags":["pdf","encryption","tagged-pdf","accessibility","security"],"backgroundTag":null,"analyzedSha":"a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8","analyzedAt":"2026-08-14T05:22:03.953Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}