{"record":{"id":"62fb90b25aebfa2d","repo":"languagetool-org/languagetool","slug":"a-separator-character-fsa-dict-separator-must-be-62fb90","errorCode":null,"errorMessage":"A separator character (fsa.dict.separator) must be defined in the dictionary info file.","messagePattern":"A separator character \\(fsa\\.dict\\.separator\\) must be defined in the dictionary info file\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"languagetool-tools/src/main/java/org/languagetool/tools/DictionaryExporter.java","lineNumber":92,"sourceCode":"      System.out.println(\"Running Morfologik FSADecompile.main with these options: \" + Arrays.toString(buildOptions));\n      FSADecompile.main(buildOptions);      \n    } else {\n      String[] buildOptions = {\"--exit\", \"false\",\n          \"-i\", binaryDictFile.toString(), \n          \"-o\", tmpOutputFile.toString()\n      };\n      System.out.println(\"Running Morfologik DictDecompile.main with these options: \" + Arrays.toString(buildOptions));\n      DictDecompile.main(buildOptions);\n    }\n    outputSeparatorToTab(tmpOutputFile);\n    System.out.println(\"Done. The dictionary export has been written to \" + getOutputFilename());\n  }\n  \n  protected void outputSeparatorToTab(File inputFile) throws RuntimeException, IOException {\n    File outputFile = new File(getOutputFilename());\n    String separator = getOption(\"fsa.dict.separator\");\n    if (separator == null || separator.trim().isEmpty()) {\n      throw new IOException(\n          \"A separator character (fsa.dict.separator) must be defined in the dictionary info file.\");\n    }\n    boolean hasFrequency = isOptionTrue(\"fsa.dict.frequency-included\");\n    String encoding = getOption(\"fsa.dict.encoding\");\n    \n    try (Scanner scanner = new Scanner(inputFile, encoding);\n         Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), encoding))) {\n      while (scanner.hasNextLine()) {\n        String line = scanner.nextLine();\n        String[] parts = line.split(Pattern.quote(separator));\n        if (parts.length == 3) {\n          if (hasFrequency) { // remove frequency data in the last byte\n            parts[2] = parts[2].substring(0, parts[2].length() - 1);\n          }\n          out.write(parts[1] + \"\\t\" + parts[0] + \"\\t\" + parts[2] + \"\\n\");\n        } else if (parts.length == 2) {\n//          if (hasFrequency) {\n//            out.write(parts[1] + \"\\n\");","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-tools/src/main/java/org/languagetool/tools/DictionaryExporter.java#L74-L110","documentation":"Configuration guard during dictionary export: the .info file lacks fsa.dict.separator, so outputSeparatorToTab cannot know which character to convert to tabs when dumping the FSA contents.","triggerScenarios":"Thrown at languagetool-tools/src/main/java/org/languagetool/tools/DictionaryExporter.java:92 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Add fsa.dict.separator=<char> to the dictionary .info file","Ensure the info file passed to DictionaryExporter is the one matching the binary dictionary"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}