stanfordnlp/CoreNLP · error · RuntimeIOException
Should have FeatureFactory but got
Error message
Should have FeatureFactory but got
What it means
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.
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.
Example fix
// before classpath: stanford-corenlp-3.9.2.jar:stanford-classifier-4.0.0.jar // mixed versions // after classpath: stanford-corenlp-4.0.0.jar // single consistent version matching the model
Defensive patterns
Strategy: try-catch
Validate before calling
// Detect duplicate/conflicting Stanford jars before loading
Set<String> seen = new HashSet<>();
for (URL url : ((URLClassLoader) CRFClassifier.class.getClassLoader()).getURLs())
if (url.getPath().matches(".*(stanford-.*|classifier|corenlp).*jar") && !seen.add(new File(url.getPath()).getName()))
throw new IllegalStateException("Duplicate Stanford jars on classpath: " + seen);
Try / catch
try {
crf.loadClassifier(modelFile, props);
} catch (RuntimeIOException e) {
if (String.valueOf(e.getMessage()).startsWith("Should have FeatureFactory"))
throw new IllegalStateException("Model/classpath version mismatch — align Stanford NLP jar version with the model", e);
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- java.lang.ClassNotFoundException
- Error loading classifier from
- Error initializing FeatureExtractorRunner
- RuntimeException wrapping Exception (dataset read failure)
- Error leading weights from {modelFile}
AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10).
Data as JSON: /api/errors/251a2be5e14d038e.
Report an issue: GitHub.
Appendix: source
Thrown at src/edu/stanford/nlp/ie/crf/CRFClassifier.java:2588
if (featureFactory instanceof List) {
featureFactories = ErasureUtils.uncheckedCast(featureFactories);
// int i = 0;
// for (FeatureFactory ff : featureFactories) { // XXXX
// System.err.println("List FF #" + i + ": " + ((NERFeatureFactory) ff).describeDistsimLexicon()); // XXXX
// i++;
// }
} else if (featureFactory instanceof FeatureFactory) {
featureFactories = Generics.newArrayList();
featureFactories.add((FeatureFactory<IN>) featureFactory);
// System.err.println(((NERFeatureFactory) featureFactory).describeDistsimLexicon()); // XXXX
} else if (featureFactory instanceof Integer) {
// this is the current format (2014) since writing list didn't work (see note in serializeClassifier).
int size = (Integer) featureFactory;
featureFactories = Generics.newArrayList(size);
for (int i = 0; i < size; ++i) {
featureFactory = ois.readObject();
if (!(featureFactory instanceof FeatureFactory)) {
throw new RuntimeIOException("Should have FeatureFactory but got " + featureFactory.getClass());
}
// System.err.println("FF #" + i + ": " + ((NERFeatureFactory) featureFactory).describeDistsimLexicon()); // XXXX
featureFactories.add((FeatureFactory<IN>) featureFactory);
}
}
// log.info("properties passed into CRF's loadClassifier are:" + props);
if (props != null) {
flags.setProperties(props, false);
}
windowSize = ois.readInt();
Object tempWeights = ois.readObject();
if (tempWeights instanceof double[][]) {
// TODO: if slow, maybe use some temp variables for the arrays
double[][] dWeights = (double[][]) tempWeights;
weights = new float[dWeights.length][];
for (int i = 0; i < dWeights.length; ++i) {View on GitHub (pinned to 1b7edd19c4)