languagetool-org/languagetool · error · RuntimeException

Could not parse XML: ${xml}

Error message

Could not parse XML: ${xml}

What it means

AfterTheDeadlineChecker wraps any exception thrown while parsing the After the Deadline service's XML response into a RuntimeException with the raw XML appended. It is thrown in getDocument when DocumentBuilder.parse fails, meaning the HTTP response body was not well-formed XML. The raw response is included in the message to aid debugging of malformed or unexpected server output.

Source

Thrown at languagetool-wikipedia/src/main/java/org/languagetool/dev/dumpcheck/AfterTheDeadlineChecker.java:113

    XPath xPath = XPathFactory.newInstance().newXPath();
    NodeList errors = (NodeList)xPath.evaluate("//error", document, XPathConstants.NODESET);
    for (int i = 0; i < errors.getLength(); i++) {
      Node error = errors.item(i);
      String string = xPath.evaluate("string", error);
      String description = xPath.evaluate("description", error);
      matches.add(description + ": " + string);
    }
    return matches;
  }

  private Document getDocument(String xml) {
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      InputSource inputSource = new InputSource(new StringReader(xml));
      return builder.parse(inputSource);
    } catch (Exception e) {
      throw new RuntimeException("Could not parse XML: " + xml, e);
    }
  }

  public static void main(String[] args) throws Exception {
    if (args.length < 4) {
      System.out.println("Usage: " + AfterTheDeadlineChecker.class.getSimpleName() + " <langCode> <atdUrlPrefix> <file...>");
      System.out.println("   <langCode>      a language code like 'en' for English");
      System.out.println("   <atdUrlPrefix>  URL prefix of After the Deadline server, like 'http://localhost:1059/checkDocument?data='");
      System.out.println("   <sentenceLimit> Maximum number of sentences to check, or 0 for no limit");
      System.out.println("   <file...>       Wikipedia and/or Tatoeba file(s)");
      System.exit(1);
    }
    Language language = Languages.getLanguageForShortCode(args[0]);
    String urlPrefix = args[1];
    int maxSentenceCount = Integer.parseInt(args[2]);
    List<String> files = Arrays.asList(args).subList(3, args.length);
    AfterTheDeadlineChecker atdChecker = new AfterTheDeadlineChecker(urlPrefix, maxSentenceCount);
    atdChecker.run(language, files);

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Print/log the raw XML from the exception message to see what was actually returned
  2. Verify the atdUrlPrefix points to a working After the Deadline instance (test the URL in a browser/curl)
  3. Check the ATD server is up and not returning an HTML error page (HTTP status, proxy)
  4. Validate encoding of the response and that it is complete (no truncation)

Example fix

// before
Document doc = checker.getDocument(xml);
// after
if (xml == null || xml.trim().isEmpty() || !xml.trim().startsWith("<?xml") && !xml.trim().startsWith("<")) {
  throw new IllegalStateException("ATD returned non-XML response: " + StringUtils.abbreviate(xml, 200));
}
Document doc = checker.getDocument(xml);
Defensive patterns

Strategy: validation

Validate before calling

if (xml == null || xml.trim().isEmpty() || !(xml.trim().startsWith("<?xml") || xml.trim().startsWith("<"))) {
  throw new IllegalStateException("ATD did not return XML: " + StringUtils.abbreviate(xml, 200));
}

Type guard

static boolean looksLikeXml(String s) {
  return s != null && s.trim().startsWith("<");
}

Try / catch

try {
  Document doc = checker.getDocument(xml);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Could not parse XML")) {
    log.warn("ATD response not parseable, skipping", e);
  } else throw e;
}

Prevention

When it happens

Trigger: The ATD server returns HTML (e.g. an error page, proxy block page, or 404 body) instead of XML; the response is truncated or empty; or the response contains characters invalid in XML (bad encoding).

Common situations: Wrong atdUrlPrefix pointing at a non-ATD endpoint or behind a captive proxy; ATD server temporarily down returning an error page; network middleware injecting content; version changes in the ATD API output format.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/6923ad8cc5928815. Report an issue: GitHub.