{"record":{"id":"aba2facb27e123e9","repo":"infinilabs/analysis-ik","slug":"ik-dict-has-not-been-initialized-yet-please-call","errorCode":null,"errorMessage":"ik dict has not been initialized yet, please call initial method first.","messagePattern":"ik dict has not been initialized yet, please call initial method first\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/wltea/analyzer/dic/Dictionary.java","lineNumber":293,"sourceCode":"\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn remoteExtStopWordDictFiles;\r\n\t}\r\n\r\n\tprivate String getDictRoot() {\r\n\t\treturn conf_dir.toAbsolutePath().toString();\r\n\t}\r\n\r\n\r\n\t/**\r\n\t * 获取词典单子实例\r\n\t * \r\n\t * @return Dictionary 单例对象\r\n\t */\r\n\tpublic static Dictionary getSingleton() {\r\n\t\tif (singleton == null) {\r\n\t\t\tthrow new IllegalStateException(\"ik dict has not been initialized yet, please call initial method first.\");\r\n\t\t}\r\n\t\treturn singleton;\r\n\t}\r\n\r\n\r\n\t/**\r\n\t * 批量加载新词条\r\n\t * \r\n\t * @param words\r\n\t *            Collection<String>词条列表\r\n\t */\r\n\tpublic void addWords(Collection<String> words) {\r\n\t\tif (words != null) {\r\n\t\t\tfor (String word : words) {\r\n\t\t\t\tif (word != null) {\r\n\t\t\t\t\t// 批量加载词条到主内存词典中\r\n\t\t\t\t\tsingleton._MainDict.fillSegment(word.trim().toCharArray());\r\n\t\t\t\t}\r","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/infinilabs/analysis-ik/blob/6d2d70fd1a237cbf75cde254e8e4d6319b81266c/core/src/main/java/org/wltea/analyzer/dic/Dictionary.java#L275-L311","documentation":"Dictionary is a singleton that must be primed by the static method Dictionary.initial(Configuration) before any dictionary-dependent API runs; getSingleton() throws IllegalStateException when that initialization has not happened. Most library code paths (CJKSegmenter, CN_QuantifierSegmenter, AnalyzeContext stopword filtering, Monitor reload) call Dictionary.getSingleton() internally, so the exception usually surfaces from inside a tokenization call rather than from user code directly.","triggerScenarios":"Calling Dictionary.getSingleton(), or any API that reaches it — new IKAnalyzer(...)/IKTokenizer tokenization, addWords/removeWords, Dictionary.matchInMainDict — before Dictionary.initial(cfg) has run anywhere in the JVM. Because singleton is a static field, this also happens in tests that fork/reset state or when a classloader boundary creates a second, uninitialized copy of the Dictionary class (e.g. some plugin containers).","commonSituations":"Upgrading from a classic IK Analyzer version where getSingleton() lazily self-initialized with DefaultConfig to this fork, where initialization is explicit and lazy init was removed; unit tests that construct an IKAnalyzer without the shared TestUtils.initial step; embedding IK in an application server/OSGi bundle where a child classloader loads a fresh Dictionary class after the parent-initialized one; multi-threaded first use racing initialization is safe (initial is synchronized) but zero use before first tokenization is not.","solutions":["Call Dictionary.initial(DefaultConfig.getInstance()) once at application/test startup (static initializer, @BeforeAll, or context-listener) before the first IKAnalyzer/IKTokenizer use","For custom configuration (ext/remote dictionaries), build your Configuration (e.g. DefaultConfig with a known conf dir) and pass that to initial instead of the default","If the error appears mid-run in a container environment, check for duplicate IK jars across classloaders and keep exactly one copy so the initialized singleton and the consumers are the same class","Wrap first-use in a small ensureInitialized() helper so every entry point cheaply guarantees initial was called"],"exampleFix":"// before — throws IllegalStateException on first token\nIKAnalyzer analyzer = new IKAnalyzer(true);\nanalyzer.tokenize(...);\n\n// after — initialize the singleton once before first use\nDictionary.initial(DefaultConfig.getInstance());\nIKAnalyzer analyzer = new IKAnalyzer(true);\nanalyzer.tokenize(...);","handlingStrategy":"validation","validationCode":"private static volatile boolean ikInitialized;\nstatic void ensureIkInitialized() {\n    if (!ikInitialized) {\n        synchronized (IkInit.class) {\n            if (!ikInitialized) {\n                Dictionary.initial(DefaultConfig.getInstance());\n                ikInitialized = true;\n            }\n        }\n    }\n}\n// call ensureIkInitialized() before creating IKAnalyzer or touching Dictionary","typeGuard":null,"tryCatchPattern":"try {\n    Dictionary.getSingleton().addWords(words);\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"not been initialized\")) {\n        Dictionary.initial(DefaultConfig.getInstance());\n        Dictionary.getSingleton().addWords(words); // retry once after init\n    } else {\n        throw e;\n    }\n}","preventionTips":["Initialize the dictionary in a static initializer or app lifecycle hook so it cannot be skipped","In test suites, put Dictionary.initial in a shared @BeforeAll rather than each test constructing analyzers ad hoc","Keep exactly one copy of the IK jar in the classpath/classloader hierarchy to avoid a second uninitialized Dictionary class","Document that this fork requires explicit Dictionary.initial — older IK versions self-initialized lazily, so copied-in legacy code will break"],"tags":["java","ik-analyzer","initialization","singleton","lifecycle"],"backgroundTag":null,"analyzedSha":"6d2d70fd1a237cbf75cde254e8e4d6319b81266c","analyzedAt":"2026-08-14T14:39:54.684Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}