languagetool-org/languagetool · error · IOException

Cannot load or parse input stream of '${filename}'

Error message

Cannot load or parse input stream of '${filename}'

What it means

PatternRuleLoader.getRules() wraps any exception thrown while SAX-parsing a pattern rule XML file into an IOException with the filename in the message. LanguageTool throws it whenever the rule XML cannot be read or is not valid XML. The original cause is chained, so inspect e.getCause() for the real XML error.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/PatternRuleLoader.java:82

   * @param filename used only for verbose exception message - should refer to where the stream comes from
   */
  public final List<AbstractPatternRule> getRules(InputStream is, String filename, Language lang) throws IOException {
    try {
      PatternRuleHandler handler = new PatternRuleHandler(filename, lang);
      handler.setRelaxedMode(relaxedMode);
      SAXParserFactory factory = SAXParserFactory.newInstance();
      SAXParser saxParser = factory.newSAXParser();
      if (JLanguageTool.isCustomPasswordAuthenticatorUsed()) {
        Tools.setPasswordAuthenticator();
      }
      saxParser.getXMLReader().setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
      saxParser.getXMLReader().setProperty("jdk.xml.maxGeneralEntitySizeLimit", 0);
      saxParser.getXMLReader().setProperty("jdk.xml.totalEntitySizeLimit", 0);
      saxParser.getXMLReader().setProperty("jdk.xml.entityExpansionLimit", 0);
      saxParser.parse(is, handler);
      return handler.getRules();
    } catch (Exception e) {
      throw new IOException("Cannot load or parse input stream of '" + filename + "'", e);
    }
  }

}

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Inspect the chained cause (e.getCause()) to find the exact XML parse error and line number, then fix the XML syntax in the rule file.
  2. Verify the file exists on the classpath/disk and the InputStream is valid and not already consumed before calling getRules.
  3. Ensure the XML is well-formed and matches the expected rule DTD/structure, including proper encoding declaration.
  4. Catch the IOException at the call site and surface a user-friendly message naming the offending rule file.

Example fix

// before
List<Rule> rules = loader.getRules(is, "myRules.xml");
// after
if (is == null || is.read() == -1) { throw new IllegalStateException("myRules.xml missing or empty"); }
try {
  List<Rule> rules = loader.getRules(is, "myRules.xml");
} catch (IOException e) {
  logger.error("Invalid rule file myRules.xml: " + e.getCause(), e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before loading
File f = new File("myRules.xml");
if (!f.isFile() || f.length() == 0) throw new IllegalStateException("Rule file missing/empty: " + f);
try (InputStream is = new BufferedInputStream(new FileInputStream(f))) { /* validate XML with a parser first */ }

Try / catch

try {
  rules = loader.getRules(is, filename);
} catch (IOException e) {
  throw new RuleLoadException("Bad rule file " + filename + ": " + e.getCause(), e);
}

Prevention

When it happens

Trigger: Calling getRules(InputStream, String filename) where the stream is unreadable, empty, closed, or contains malformed XML (e.g. PatternRuleLoaderHandler fails on bad element/attribute), including during externalRules/loadPatternRules/initializePatternRules.

Common situations: Typo or unescaped character (&, <) in a custom grammar .xml rule file; missing file packaged into resources; encoding mismatch (file not UTF-8); corrupted stream after an earlier read; entity limits were configured away in this version (jdk.xml.maxGeneralEntitySizeLimit etc. set to 0).

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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