{"record":{"id":"251a2be5e14d038e","repo":"stanfordnlp/CoreNLP","slug":"should-have-featurefactory-but-got","errorCode":null,"errorMessage":"Should have FeatureFactory but got ","messagePattern":"Should have FeatureFactory but got ","errorType":"exception","errorClass":"RuntimeIOException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/ie/crf/CRFClassifier.java","lineNumber":2588,"sourceCode":"    if (featureFactory instanceof List) {\n      featureFactories = ErasureUtils.uncheckedCast(featureFactories);\n//      int i = 0;\n//      for (FeatureFactory ff : featureFactories) { // XXXX\n//        System.err.println(\"List FF #\" + i + \": \" + ((NERFeatureFactory) ff).describeDistsimLexicon()); // XXXX\n//        i++;\n//      }\n    } else if (featureFactory instanceof FeatureFactory) {\n      featureFactories = Generics.newArrayList();\n      featureFactories.add((FeatureFactory<IN>) featureFactory);\n//      System.err.println(((NERFeatureFactory) featureFactory).describeDistsimLexicon()); // XXXX\n    } else if (featureFactory instanceof Integer) {\n      // this is the current format (2014) since writing list didn't work (see note in serializeClassifier).\n      int size = (Integer) featureFactory;\n      featureFactories = Generics.newArrayList(size);\n      for (int i = 0; i < size; ++i) {\n        featureFactory = ois.readObject();\n        if (!(featureFactory instanceof FeatureFactory)) {\n          throw new RuntimeIOException(\"Should have FeatureFactory but got \" + featureFactory.getClass());\n        }\n//        System.err.println(\"FF #\" + i + \": \" + ((NERFeatureFactory) featureFactory).describeDistsimLexicon()); // XXXX\n        featureFactories.add((FeatureFactory<IN>) featureFactory);\n      }\n    }\n\n    // log.info(\"properties passed into CRF's loadClassifier are:\" + props);\n    if (props != null) {\n      flags.setProperties(props, false);\n    }\n\n    windowSize = ois.readInt();\n    Object tempWeights = ois.readObject();\n    if (tempWeights instanceof double[][]) {\n      // TODO: if slow, maybe use some temp variables for the arrays\n      double[][] dWeights = (double[][]) tempWeights;\n      weights = new float[dWeights.length][];\n      for (int i = 0; i < dWeights.length; ++i) {","sourceCodeStart":2570,"sourceCodeEnd":2606,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/ie/crf/CRFClassifier.java#L2570-L2606","documentation":"While deserializing a classifier, CRFClassifier reads the serialized feature factory objects; since the 2014 format stores a count then each FeatureFactory instance. If an element read back is not an instanceof FeatureFactory, it throws RuntimeIOException('Should have FeatureFactory but got <class>'). This means the stream's feature-factory section is corrupted or was written by an incompatible version/class layout.","triggerScenarios":"loadClassifier / loadClassifierFromObjectStream on a serialized classifier whose featureFactory slot deserializes to a wrong class — e.g. model serialized with different NERFeatureFactory classes, classpath containing a conflicting Stanford NLP version, or corrupted/truncated stream.","commonSituations":"Multiple stanford-corenlp/stanford-classifier jars on the classpath causing wrong FeatureFactory class to load; deserializing a model from a very different library version; corrupted model file; custom feature factory not extending FeatureFactory at serialization time.","solutions":["Check the classpath for duplicate/conflicting stanford jars and keep a single consistent version that matches the model.","Verify the model file integrity (size, checksum) and re-download/re-serialize it.","Use the same Stanford NLP release to read the model as the one that wrote it.","If a custom FeatureFactory was used at training time, ensure it is on the classpath and extends FeatureFactory.","Reserialize the classifier with the current version (load with old version, then serializeClassifier) to migrate formats."],"exampleFix":"// before\nclasspath: stanford-corenlp-3.9.2.jar:stanford-classifier-4.0.0.jar  // mixed versions\n// after\nclasspath: stanford-corenlp-4.0.0.jar  // single consistent version matching the model","handlingStrategy":"try-catch","validationCode":"// Detect duplicate/conflicting Stanford jars before loading\nSet<String> seen = new HashSet<>();\nfor (URL url : ((URLClassLoader) CRFClassifier.class.getClassLoader()).getURLs())\n  if (url.getPath().matches(\".*(stanford-.*|classifier|corenlp).*jar\") && !seen.add(new File(url.getPath()).getName()))\n    throw new IllegalStateException(\"Duplicate Stanford jars on classpath: \" + seen);\n","typeGuard":null,"tryCatchPattern":"try {\n  crf.loadClassifier(modelFile, props);\n} catch (RuntimeIOException e) {\n  if (String.valueOf(e.getMessage()).startsWith(\"Should have FeatureFactory\"))\n    throw new IllegalStateException(\"Model/classpath version mismatch — align Stanford NLP jar version with the model\", e);\n  throw e;\n}","preventionTips":["Keep exactly one Stanford NLP jar version on the classpath, matching the model's version.","Verify model file checksums after download.","Place custom FeatureFactory classes on the classpath at load time.","Migrate models by reserializing with the current version."],"tags":["java","deserialization","classpath","feature-factory"],"backgroundTag":"class-not-found","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"}