{"record":{"id":"53f9ba23282fc3f9","repo":"elastic/elasticsearch","slug":"cannot-merge-search-time-and-index-time-analysis-m","errorCode":null,"errorMessage":"Cannot merge SEARCH_TIME and INDEX_TIME analysis mode.","messagePattern":"Cannot merge SEARCH_TIME and INDEX_TIME analysis mode\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"libs/plugin-analysis-api/src/main/java/org/elasticsearch/plugin/analysis/AnalysisMode.java","lineNumber":26,"sourceCode":" */\n\npackage org.elasticsearch.plugin.analysis;\n\n/**\n * Enum representing the mode in which token filters and analyzers are allowed to operate.\n * While most token filters are allowed both in index and search time analyzers, some are\n * restricted to be used only at index time, others at search time.\n */\npublic enum AnalysisMode {\n\n    /**\n     * AnalysisMode representing analysis components that can be used only at index time.\n     */\n    INDEX_TIME(\"index time\") {\n        @Override\n        public AnalysisMode merge(AnalysisMode other) {\n            if (other == AnalysisMode.SEARCH_TIME) {\n                throw new IllegalStateException(\"Cannot merge SEARCH_TIME and INDEX_TIME analysis mode.\");\n            }\n            return AnalysisMode.INDEX_TIME;\n        }\n    },\n    /**\n     * AnalysisMode representing analysis components that can be used only at search time.\n     */\n    SEARCH_TIME(\"search time\") {\n        @Override\n        public AnalysisMode merge(AnalysisMode other) {\n            if (other == AnalysisMode.INDEX_TIME) {\n                throw new IllegalStateException(\"Cannot merge SEARCH_TIME and INDEX_TIME analysis mode.\");\n            }\n            return AnalysisMode.SEARCH_TIME;\n        }\n    },\n    /**\n     * AnalysisMode representing analysis components that can be used both at index and search time.","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/plugin-analysis-api/src/main/java/org/elasticsearch/plugin/analysis/AnalysisMode.java#L8-L44","documentation":"Thrown by AnalysisMode.INDEX_TIME.merge(other) when other == SEARCH_TIME. AnalysisMode models whether a token filter/analyzer component is allowed at index time, search time, both (ALL), or neither (NONE). Merging INDEX_TIME with SEARCH_TIME is impossible because a single component cannot be both exclusively-index and exclusively-search; the merge throws IllegalStateException to flag an inconsistent analyzer configuration.","triggerScenarios":"A multi-component analyzer/filter chain where one component declares AnalysisMode.INDEX_TIME and another declares AnalysisMode.SEARCH_TIME, and the framework merges their modes to decide where the analyzer can run. E.g. a custom analyzer combining an index-only synonym filter with a search-only normalization filter.","commonSituations":"Adding a search-only filter (e.g. some stemmer variants) to an analyzer also used at index time, or vice-versa; plugin authors setting the wrong AnalysisMode on a token filter; upgrading a filter whose mode changed between versions.","solutions":["Split the analyzer into separate index-time and search-time configurations so no single chain mixes INDEX_TIME and SEARCH_TIME components.","Re-check each component's declared AnalysisMode and switch the offending one to ALL if it is genuinely usable at both phases.","If you author the component, set AnalysisMode to match its real capabilities rather than over-restricting it.","Validate the analyzer definition at config-load time and report which two filters conflict by name."],"exampleFix":"// before: one analyzer mixes modes\n\"analysis\": {\n  \"analyzer\": { \"my\": { \"filter\": [\"index_only_syn\", \"search_only_norm\"] } }\n}\n\n// after: separate analyzers per phase\n\"analysis\": {\n  \"analyzer\": {\n    \"my_index\": { \"filter\": [\"index_only_syn\"] },\n    \"my_search\": { \"filter\": [\"search_only_norm\"] }\n  }\n}","handlingStrategy":"validation","validationCode":"// Walk the analyzer's filter chain and reject conflicting AnalysisMode merges up front.\nAnalysisMode acc = AnalysisMode.ALL;\nfor (AnalysisComponent c : filters) {\n    AnalysisMode m = c.analysisMode();\n    if ((acc == AnalysisMode.INDEX_TIME && m == AnalysisMode.SEARCH_TIME)\n     || (acc == AnalysisMode.SEARCH_TIME && m == AnalysisMode.INDEX_TIME)) {\n        throw new IllegalArgumentException(\"Analyzer mixes INDEX_TIME and SEARCH_TIME filters: \" + c.name());\n    }\n    acc = acc.merge(m);\n}","typeGuard":null,"tryCatchPattern":"try {\n    AnalysisMode merged = a.merge(b);\n} catch (IllegalStateException e) {\n    throw new IllegalArgumentException(\"Cannot build analyzer: index-only and search-only filters are incompatible\", e);\n}","preventionTips":["Split analyzers into index-time and search-time configurations.","Default custom token filters to AnalysisMode.ALL unless they truly cannot run in one phase.","Validate the filter chain at config-load time and report the conflicting pair."],"tags":["analysis","plugin-api","analyzer","configuration"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}