{"record":{"id":"28290651ad04892c","repo":"skylot/jadx","slug":"failed-to-parse-xml","errorCode":null,"errorMessage":"Failed to parse xml","messagePattern":"Failed to parse xml","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"jadx-core/src/main/java/jadx/api/security/impl/JadxSecurity.java","lineNumber":113,"sourceCode":"\t\tMatcher matcher = SANITIZE_GRADLE_PATTERN.matcher(str);\n\t\tif (matcher.find()) {\n\t\t\treturn matcher.replaceAll(\"\");\n\t\t}\n\t\treturn str;\n\t}\n\n\t@Override\n\tpublic Document parseXml(InputStream in) {\n\t\tDocumentBuilderFactory dbf;\n\t\tif (flags.contains(JadxSecurityFlag.SECURE_XML_PARSER)) {\n\t\t\tdbf = SecureDBFHolder.INSTANCE;\n\t\t} else {\n\t\t\tdbf = SimpleDBFHolder.INSTANCE;\n\t\t}\n\t\ttry {\n\t\t\treturn dbf.newDocumentBuilder().parse(in);\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(\"Failed to parse xml\", e);\n\t\t}\n\t}\n\n\tprivate static final class SimpleDBFHolder {\n\t\tprivate static final DocumentBuilderFactory INSTANCE = DocumentBuilderFactory.newInstance();\n\t}\n\n\tprivate static final class SecureDBFHolder {\n\t\tprivate static final DocumentBuilderFactory INSTANCE = buildSecureDBF();\n\n\t\tprivate static DocumentBuilderFactory buildSecureDBF() {\n\t\t\ttry {\n\t\t\t\tDocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n\t\t\t\tdbf.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", true);\n\t\t\t\tdbf.setFeature(\"http://apache.org/xml/features/nonvalidating/load-external-dtd\", false);\n\t\t\t\tdbf.setFeature(\"http://xml.org/sax/features/external-general-entities\", false);\n\t\t\t\tdbf.setFeature(\"http://xml.org/sax/features/external-parameter-entities\", false);\n\t\t\t\tdbf.setFeature(\"http://apache.org/xml/features/dom/create-entity-ref-nodes\", false);","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/api/security/impl/JadxSecurity.java#L95-L131","documentation":"Thrown by JadxSecurity.parseXml when the underlying DocumentBuilder.parse(in) call fails for any reason (SAXException, IOException, IllegalArgumentException, etc.). Jadx wraps all exceptions in a generic RuntimeException because parseXml is called from multiple code paths (AndroidManifest.xml, resource XML, etc.) that do not declare checked exceptions. The secure vs. simple factory is selected by the SECURE_XML_PARSER flag but both paths share the same catch.","triggerScenarios":"Calling parseXml(in) with a stream containing malformed XML, non-XML binary data, truncated content, or an unsupported encoding declaration. Also triggered if the InputStream throws IOException during reading, or if the input is null (though a null stream typically yields a different NullPointerException before the catch). The secure parser may additionally reject XML with DTD or external entity references.","commonSituations":"Decompiling an APK whose AndroidManifest.xml or resources.arsc XML is corrupted or obfuscated. Binary XML (AXML format) fed to parseXml instead of text XML. A truncated or partially downloaded APK where the XML resource is incomplete. Custom jadx integrations that pass unvalidated streams to parseXml.","solutions":["Inspect getCause() — a SAXException indicates malformed XML content; an IOException indicates stream reading failure.","Validate the input is well-formed text XML before calling parseXml, especially if the source may be binary AXML (convert it first with the AXML decoder).","If the SECURE_XML_PARSER flag is set and DTD/external entities are legitimately needed (rare), disable that flag — but be aware of XXE risks.","Catch the RuntimeException around parseXml and log the offending resource name so processing of the rest of the APK can continue."],"exampleFix":"// before\nDocument doc = jadxSecurity.parseXml(inputStream);\n\n// after: validate and handle\nDocument doc;\ntry {\n    doc = jadxSecurity.parseXml(inputStream);\n} catch (RuntimeException e) {\n    LOG.warn(\"Failed to parse XML resource\", e.getCause());\n    doc = null; // or skip resource\n}","handlingStrategy":"try-catch","validationCode":"// Pre-validate that the stream contains text XML, not binary AXML\nbyte[] first = new byte[5];\ninputStream.mark(5);\nint read = inputStream.read(first);\ninputStream.reset();\nif (read >= 1 && first[0] == 0x03) { // binary AXML magic number\n    throw new IllegalArgumentException(\"Input is binary AXML, not text XML — convert first\");\n}","typeGuard":null,"tryCatchPattern":"Document doc;\ntry {\n    doc = jadxSecurity.parseXml(inputStream);\n} catch (RuntimeException e) {\n    Throwable cause = e.getCause();\n    if (cause instanceof org.xml.sax.SAXException) {\n        LOG.warn(\"Malformed XML: {}\", cause.getMessage());\n    } else if (cause instanceof java.io.IOException) {\n        LOG.warn(\"IO error reading XML: {}\", cause.getMessage());\n    }\n    doc = null;\n}","preventionTips":["Validate that input is text XML, not binary AXML, before calling parseXml — check for the 0x03 magic byte.","Catch RuntimeException (not checked exceptions) around parseXml since it wraps all failures.","Log the cause (not the wrapper) to distinguish SAX parse errors from IO errors."],"tags":["xml","security","parse","io"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}