{"record":{"id":"c02889a3dd7e8e75","repo":"languagetool-org/languagetool","slug":"factor-must-be-0-score","errorCode":null,"errorMessage":"factor must be > 0: \" + score","messagePattern":"factor must be > 0: \" \\+ score","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/ScoredConfusionSet.java","lineNumber":43,"sourceCode":"\n/**\n * Words that can easily be confused - for internal use only.\n * Even though there can be more words in the confusionWords, usually there\n * are two, as the factor is specific for this pair of words.\n * A ScoredConfusionSet has a positive score associated with it.\n * TODO remove code duplication with ConfusionSet\n */\npublic class ScoredConfusionSet {\n\n  private List<ConfusionString> confusionWords;\n  private final float score;\n\n  /**\n   * @param score the score that a string must get at least to be considered a correction, must be &gt; 0\n   */\n  public ScoredConfusionSet(float score, List<ConfusionString> words) {\n    if (score <= 0) {\n      throw new IllegalArgumentException(\"factor must be > 0: \" + score);\n    }\n    this.score = score;\n    confusionWords = words;\n  }\n\n  /* Alternative must be at least this much more probable to be considered correct. */\n  public float getScore() {\n    return score;\n  }\n\n  public List<String> getConfusionTokens() {\n    return confusionWords.stream().map(ConfusionString::getString).collect(Collectors.toList());\n  }\n\n  public List<Optional<String>> getTokenDescriptions() {\n    return confusionWords.stream()\n            .map(ConfusionString::getDescription)\n            .map(Optional::ofNullable)","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/ScoredConfusionSet.java#L25-L61","documentation":"ScoredConfusionSet's constructor documents that the score/factor threshold must be strictly greater than 0; a score <= 0 would make every alternative 'considered correct' vacuously or nonsensically, so it throws IllegalArgumentException with this message.","triggerScenarios":"Instantiating new ScoredConfusionSet(score, words) with score = 0, negative, or NaN-derived value <= 0, e.g. from a mis-parsed config value or default initialization.","commonSituations":"Confusion-set rules loaded from data files where the score column was missing/zero, float parsing of empty strings yielding 0, or copy-pasted example code with a placeholder score.","solutions":["Pass a positive score (e.g. 0.5f) when constructing ScoredConfusionSet.","Check the source data/config that supplies the score; fix zero or negative entries.","Add a caller-side guard or default (e.g. Math.max(score, MIN_SCORE)) before constructing."],"exampleFix":"// before\nfloat score = Float.parseFloat(props.getProperty(\"factor\", \"0\"));\nScoredConfusionSet set = new ScoredConfusionSet(score, words);\n// after\nfloat score = Float.parseFloat(props.getProperty(\"factor\", \"1.0\"));\nif (score <= 0) throw new IllegalArgumentException(\"confusion set factor must be > 0\");\nScoredConfusionSet set = new ScoredConfusionSet(score, words);","handlingStrategy":"validation","validationCode":"if (!(score > 0) || Float.isNaN(score)) {\n  throw new IllegalArgumentException(\"ScoredConfusionSet score must be > 0, got: \" + score);\n}","typeGuard":"boolean isValidScore(float score) { return score > 0.0f && !Float.isNaN(score); }","tryCatchPattern":"try {\n  set = new ScoredConfusionSet(score, words);\n} catch (IllegalArgumentException e) {\n  LOG.warn(\"Falling back to default score: {}\", e.getMessage());\n  set = new ScoredConfusionSet(1.0f, words);\n}","preventionTips":["Never default the score to 0 — use a sane positive default","Sanity-check parsed floats from data files (NaN/0/empty inputs)","Document the >0 constraint wherever the score is configured"],"tags":["java","languagetool","illegal-argument","confusion-set"],"backgroundTag":"argument-out-of-range","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}