languagetool-org/languagetool · error · RuntimeException

IOException while synthesizing suggestions (verb-noun…

Error message

IOException while synthesizing suggestions (verb-noun agreement)

What it means

TokenAgreementVerbNounRule.getSuggestions() (used by the suggestions flow) rewrites the verb posTag and calls synthesizer.synthesize(analyzedToken, posTag, true) to produce agreeing verb forms; IOException is wrapped in RuntimeException. A failure means the Morfologik synthesizer could not read its dictionary while generating verb inflections.

Solutions

  1. Diagnose the original IOException from the cause chain (resource path, permissions, disk).
  2. Validate and rebuild the language-module jar so dictionary binaries are intact.
  3. Return an empty suggestion list on synthesis failure so the grammar error is still reported.
  4. Add a startup synthesizer smoke test and alert if it fails.
  5. Keep binary dictionary resources out of any resource-filtering in the build.

Example fix

// before
String[] synthesized = synthesizer.synthesize(analyzedToken, posTag, true);
// after
String[] synthesized;
try {
  synthesized = synthesizer.synthesize(analyzedToken, posTag, true);
} catch (IOException e) {
  LOG.warn("verb synthesis failed; no suggestions", e);
  synthesized = new String[0];
}
Defensive patterns

Strategy: try-catch

Validate before calling

// startup check
try {
  String[] t = synthesizer.synthesize(new AnalyzedToken("бачив", "verb:perf:past:m", "бачити"), "verb:perf:past:f", true);
  if (t.length == 0) LOG.warn("Verb synthesis returned no forms");
} catch (IOException e) { throw new IllegalStateException("Verb synthesizer dictionary broken", e); }

Try / catch

try { suggestions = rule.getSuggestions(tokens); }
catch (RuntimeException e) {
  if (e.getCause() instanceof IOException) { LOG.warn("verb-noun synthesis failed", e); suggestions = Collections.emptyList(); }
  else throw e;
}

Prevention

When it happens

Trigger: Verb-noun disagreement detected in text; the rule builds inflected verb suggestions and the dictionary-backed synthesize() call throws IOException.

Common situations: Corrupted/missing Ukrainian dictionaries in the deployed jar; disk or volume I/O errors; jars damaged by shading/filtering; resource exhaustion during dictionary load.

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/5d8af318812e60c8. Report an issue: GitHub.

Appendix: source

Thrown at languagetool-language-modules/uk/src/main/java/org/languagetool/rules/uk/TokenAgreementVerbNounRule.java:407

    
    String requiredPostTagsRegEx = ":(" + String.join("|", cases) + ")";

    Set<String> suggestions = new LinkedHashSet<>();

    for (AnalyzedToken analyzedToken: tokenReadings.getReadings()) {
    
      String oldPosTag = analyzedToken.getPOSTag();
      
      if( oldPosTag == null || ! oldPosTag.contains(":v_") )
        continue;
      
      String posTag = oldPosTag.replaceFirst(":v_[a-z]+", requiredPostTagsRegEx);

      try {
        String[] synthesized = synthesizer.synthesize(analyzedToken, posTag, true);
        suggestions.addAll( Arrays.asList(synthesized) );
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
    return new ArrayList<>(suggestions);
  }

  private String formatInflections(Set<String> cases) {
    if( cases.isEmpty() )
      return "неперех.";
    
    return "вимагає: " + cases.stream()
        .map(c -> PosTagHelper.VIDMINKY_I_MAP.get(c))
        .collect(Collectors.joining(", "));
  }

}

View on GitHub (pinned to 2e990059ce)