{"record":{"id":"007f2555bc6f440a","repo":"stanfordnlp/CoreNLP","slug":"unexpected-class-while-adding-word-in-phrase","errorCode":null,"errorMessage":"Unexpected class  while adding word () in phrase ","messagePattern":"Unexpected class  while adding word \\(\\) in phrase ","errorType":"exception","errorClass":"java.lang.RuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/ling/tokensregex/PhraseTable.java","lineNumber":355,"sourceCode":"\n  private synchronized void addPhrase(Map<String,Object> tree, Phrase phrase, int wordIndex)\n  {\n    String word = (phrase.wordList.size() <= wordIndex)? PHRASE_END:phrase.wordList.getWord(wordIndex);\n    Object node = tree.get(word);\n    if (node == null) {\n      tree.put(word, phrase);\n    } else if (node instanceof Phrase) {\n      // create list with this phrase and other and put it here\n      List<Object> list = new ArrayList<>(2);\n      list.add(phrase);\n      list.add(node);\n      tree.put(word, list);\n    } else if (node instanceof Map) {\n      addPhrase((Map<String,Object>) node, phrase, wordIndex+1);\n    } else if (node instanceof List) {\n      ((List) node).add(phrase);\n    } else {\n      throw new RuntimeException(\"Unexpected class \" + node.getClass() + \" while adding word \"\n              + wordIndex + \"(\" + word + \") in phrase \" + phrase.getText());\n    }\n  }\n\n  private synchronized boolean addPhrase(Map<String,Object> tree,\n                                         String phraseText, String tag, WordList wordList, Object phraseData, int wordIndex)\n  {\n    // Find place to insert this item\n    boolean phraseAdded = false;  // True if this phrase was successfully added to the phrase table\n    boolean newPhraseAdded = false;    // True if the phrase was a new phrase\n    boolean oldPhraseNewFormAdded = false;      // True if the phrase already exists, and this was new form added to old phrase\n    for (int i = wordIndex; i < wordList.size(); i++) {\n      String word = Interner.globalIntern(wordList.getWord(i));\n      Object node = tree.get(word);\n      if (node == null) {\n        // insert here\n        Phrase phrase = new Phrase(wordList, phraseText, tag, phraseData);\n        tree.put(word, phrase);","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/ling/tokensregex/PhraseTable.java#L337-L373","documentation":"PhraseTable's internal trie is built from nested Maps whose leaves are Lists of Phrase objects or nested Maps. addPhrase traverses the trie and throws when a node it must descend into is none of Map, List, or Phrase — a corrupted or unexpected trie node type.","triggerScenarios":"The trie node for a word was previously set to an unexpected object type (e.g. a String or Phrase where a container was required) and a longer phrase sharing that prefix is added afterwards.","commonSituations":"Concurrent/unsynchronized mutation of the trie from multiple threads (the Map overload is not synchronized) corrupting node types; custom code writing directly into the internal tree map.","solutions":["Use only the public addPhrase API; never insert raw values into the internal tree structure","Synchronize phrase-table population or build it single-threaded before use","Inspect the trie node at the failing word index to find what wrote the unexpected object"],"exampleFix":"// before (custom insertion)\n((Map) trieNode).put(word, \"someString\");\n// after\ntable.addPhrase(wordList, phraseText, tag, data); // let PhraseTable manage node types","handlingStrategy":"try-catch","validationCode":"Object node = null; // only inspect via public API; do not write into the tree directly\nif (!tableClassNodeTypesOk) rebuildTable();","typeGuard":"static boolean validTrieNode(Object n) { return n instanceof Map || n instanceof List || n instanceof Phrase; }","tryCatchPattern":"try { table.addPhrase(wordList, text, tag, data); } catch (RuntimeException e) { if (e.getMessage().startsWith(\"Unexpected class\")) { rebuildPhraseTableFromSource(); } else throw e; }","preventionTips":["Never mutate PhraseTable's internal tree directly","Populate the table single-threaded or synchronized","Rebuild the table from source files on any structural exception"],"tags":["tokensregex","internal-state","trie"],"backgroundTag":"internal-invariant-violation","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}