{"record":{"id":"648db2b95a1fef01","repo":"elastic/elasticsearch","slug":"token-filter-name-cannot-be-used-to-parse-sy-648db2","errorCode":null,"errorMessage":"Token filter [{name()}] cannot be used to parse synonyms","messagePattern":"Token filter \\[(.+?)\\] cannot be used to parse synonyms","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/analysis-common/src/main/java/org/elasticsearch/analysis/common/WordDelimiterTokenFilterFactory.java","lineNumber":96,"sourceCode":"        flags |= getFlag(PRESERVE_ORIGINAL, settings, \"preserve_original\", false);\n        // 1, causes \"j2se\" to be three tokens; \"j\" \"2\" \"se\"\n        flags |= getFlag(SPLIT_ON_NUMERICS, settings, \"split_on_numerics\", true);\n        // If set, causes trailing \"'s\" to be removed for each subword: \"O'Neil's\" => \"O\", \"Neil\"\n        flags |= getFlag(STEM_ENGLISH_POSSESSIVE, settings, \"stem_english_possessive\", true);\n        // If not null is the set of tokens to protect from being delimited\n        Set<?> protectedWords = Analysis.getWordSet(env, settings, \"protected_words\");\n        this.protoWords = protectedWords == null ? null : CharArraySet.copy(protectedWords);\n        this.flags = flags;\n    }\n\n    @Override\n    public TokenStream create(TokenStream tokenStream) {\n        return new WordDelimiterFilter(tokenStream, charTypeTable, flags, protoWords);\n    }\n\n    @Override\n    public TokenFilterFactory getSynonymFilter() {\n        throw new IllegalArgumentException(\"Token filter [\" + name() + \"] cannot be used to parse synonyms\");\n    }\n\n    public static int getFlag(int flag, Settings settings, String key, boolean defaultValue) {\n        if (settings.getAsBoolean(key, defaultValue)) {\n            return flag;\n        }\n        return 0;\n    }\n\n    // source => type\n    private static final Pattern typePattern = Pattern.compile(\"(.*)\\\\s*=>\\\\s*(.*)\\\\s*$\");\n\n    /**\n     * parses a list of MappingCharFilter style rules into a custom byte[] type table\n     */\n    static byte[] parseTypes(Collection<String> rules) {\n        SortedMap<Character, Byte> typeMap = new TreeMap<>();\n        for (String rule : rules) {","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/analysis-common/src/main/java/org/elasticsearch/analysis/common/WordDelimiterTokenFilterFactory.java#L78-L114","documentation":"WordDelimiterTokenFilterFactory.getSynonymFilter() is hard-coded to throw IllegalArgumentException, identical in spirit to the graph variant. The non-graph word-delimiter filter splits tokens in ways that break the parsing of synonym rules, so Elasticsearch refuses to use it (or any analyzer chain that resolves to it) as the synonym-parsing analyzer.","triggerScenarios":"A synonym/synonym_graph filter whose effective analyzer chain contains a word_delimiter filter; commonly when 'analyzer' is omitted and the index's default analyzer includes word_delimiter.","commonSituations":"Reusing a generic analyzer for both indexing and synonym parsing; legacy config that pre-dates the getSynonymFilter guard.","solutions":["Set an explicit \"analyzer\" on the synonym/synonym_graph filter that does not include word_delimiter (use 'standard' or 'whitespace').","Move word_delimiter into a search-specific analyzer only.","Verify with _analyze that the synonym-parsing chain emits one token per synonym term."],"exampleFix":"// before\n\"my_syn\": { \"type\": \"synonym_graph\", \"synonyms\": [\"foo,bar\"], \"analyzer\": \"my_wd_analyzer\" }\n// after\n\"my_syn\": { \"type\": \"synonym_graph\", \"synonyms\": [\"foo,bar\"], \"analyzer\": \"standard\" }","handlingStrategy":"validation","validationCode":"// Reject synonym filters that resolve to a word_delimiter analyzer\nstatic String checkSynonymAnalyzer(Map<String,Object> filter, Set<String> wdAnalyzers) {\n  if (\"synonym\".equals(filter.get(\"type\")) || \"synonym_graph\".equals(filter.get(\"type\"))) {\n    Object a = filter.getOrDefault(\"analyzer\", \"<default>\");\n    if (wdAnalyzers.contains(a)) return \"analyzer \" + a + \" contains word_delimiter\";\n  }\n  return null;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set an explicit lightweight 'analyzer' on synonym/synonym_graph filters.","Keep word_delimiter out of the index default analyzer if that analyzer is also used for synonym parsing."],"tags":["analysis","synonyms","word-delimiter","configuration"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}