{"record":{"id":"04ea02b3c6caf666","repo":"languagetool-org/languagetool","slug":"ioexception-while-synthesizing-suggestions-adj-no","errorCode":null,"errorMessage":"IOException while synthesizing suggestions (adj-noun agreement)","messagePattern":"IOException while synthesizing suggestions \\(adj-noun agreement\\)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-language-modules/uk/src/main/java/org/languagetool/rules/uk/TokenAgreementAdjNounRule.java","lineNumber":334,"sourceCode":"          }\n\n          for(AnalyzedToken adjToken: state.adjTokenReadings) {\n            String newAdjTag = adjToken.getPOSTag().replaceFirst(\":.:v_...(:r(in)?anim)?\", genderTag + vidmTag);\n\n            String[] synthesized = synthesizer.synthesize(adjToken, newAdjTag, false);\n\n            for (String s : synthesized) {\n              String suggestion = s + \" \" + tokenReadings.getToken();\n              if( ! suggestions.contains(suggestion) ) {\n                suggestions.add(suggestion);\n              }\n            }\n          }\n\n        }\n\n        } catch (IOException e) {\n          throw new RuntimeException(e);\n        }\n\n        if( msg.contains(\"кількісного числівника\") ) {\n          String suggNum = state.adjAnalyzedTokenReadings.getCleanToken().replaceFirst(\"[-–]м[аи]$\", \"\")\n              + \" \" + tokenReadings.getToken();\n          suggestions.add(suggNum);\n        }\n        \n        if( suggestions.size() > 0 ) {\n            potentialRuleMatch.setSuggestedReplacements(suggestions);\n        }\n\n        ruleMatches.add(potentialRuleMatch);\n      }\n\n      state.reset();\n    }\n","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-language-modules/uk/src/main/java/org/languagetool/rules/uk/TokenAgreementAdjNounRule.java#L316-L352","documentation":"TokenAgreementAdjNounRule.match() synthesizes inflected adjective suggestions with the Morfologik synthesizer; any IOException from synthesize() is wrapped in a RuntimeException and aborts the rule match. This is a runtime data-lookup failure, not a rule-logic error: the dictionary synthesizer failed while generating inflected forms for suggestions.","triggerScenarios":"A text is analyzed where adj-noun disagreement is detected and the rule calls synthesizer.synthesize(...) for suggestions, but the underlying dictionary stream/lookup throws IOException (broken dictionary resource, corrupt cache, I/O failure).","commonSituations":"Corrupted or partially extracted Morfologik dictionary in the deployed artifact; filesystem/disk errors when the dictionary is memory-mapped from disk; running LanguageTool on a read-only or failing volume.","solutions":["Inspect e.getCause() to find the underlying I/O failure (resource path, disk, permissions).","Verify the Ukrainian synthesizer dictionary loads correctly (run a minimal synthesize call at startup as a health check).","Rebuild/redistribute the language module jar to ensure dictionary binaries are intact.","Catch the RuntimeException at the rule-engine integration layer and degrade to reporting the disagreement without synthesized suggestions.","Avoid shading/repackaging jars in ways that corrupt binary dictionary entries."],"exampleFix":"// before\n} catch (IOException e) {\n  throw new RuntimeException(e);\n}\n// after\n} catch (IOException e) {\n  LOG.warn(\"Synthesizer failed for adj-noun suggestions; returning agreement without suggestions\", e);\n  return toRuleMatchUnsynthesized(msg);\n}","handlingStrategy":"try-catch","validationCode":"// startup health check\ntry {\n  String[] test = synthesizer.synthesize(new AnalyzedToken(\"добрий\", \"adj:m:v_naz\", \"добрий\"), \"adj:f:v_naz\", true);\n  if (test.length == 0) LOG.warn(\"Ukrainian synthesizer returned no forms\");\n} catch (IOException e) { throw new IllegalStateException(\"Synthesizer dictionary broken\", e); }","typeGuard":null,"tryCatchPattern":"try { matchResult = rule.match(tokens); }\ncatch (RuntimeException e) {\n  if (e.getCause() instanceof IOException) { LOG.error(\"Suggestion synthesis failed; degrade to no-suggestion match\", e); }\n  else throw e;\n}","preventionTips":["Smoke-test the synthesizer at service startup","Verify dictionary binaries in deployed jars (checksums)","Avoid read-only/failing volumes for dictionary storage","Degrade gracefully: report the disagreement even when suggestions can't be synthesized"],"tags":["io","synthesizer","suggestions","agreement-rule"],"backgroundTag":"file-read-failed","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}