stanfordnlp/CoreNLP · error · IllegalStateException
Unhandled primitive type in array
Error message
Unhandled primitive type in array: ${componentType} What it means
JSONOutputter's routeObject converts annotation values into JSON. It handles primitive arrays (int[], double[], boolean[], etc.) explicitly; when the array's component type is a primitive it does not handle (e.g. short[], char[], byte[], float[], long[]), an IllegalStateException is thrown because there is no conversion path.
Solutions
- Convert unsupported primitive arrays to List< boxedType > or the supported type (int[]/double[]/boolean[]) before passing to JSONOutputter
- Box the array manually (e.g. ArrayUtils.toObject or a loop into ArrayList<Long>)
- Change the annotator to store the value as a boxed array (Long[]/Float[]) or List so the Object[] branch handles it
- If this is a CoreNLP bug, file/patch the missing primitive branch in routeObject
Example fix
// before
annotations.put(CoreAnnotations.MyStats.class, new long[]{1L, 2L});
// after
annotations.put(CoreAnnotations.MyStats.class, new long[]{1L, 2L});
// ...and before outputting:
List<Long> boxed = Arrays.stream(longs).boxed().collect(Collectors.toList()); Defensive patterns
Strategy: type-guard
Validate before calling
Object v = ann.get(key);
Class<?> c = v.getClass();
if (c.isArray() && c.getComponentType().isPrimitive()
&& !(c == int[].class || c == double[].class || c == boolean[].class))
throw new IllegalArgumentException("Unsupported primitive array for JSON: " + c); Type guard
static boolean isJsonSafeArray(Object v) {
Class<?> c = v.getClass();
if (!c.isArray() || !c.getComponentType().isPrimitive()) return true;
return c == int[].class || c == double[].class || c == boolean[].class;
} Try / catch
try {
JSONOutputter.jsonPrint(writer, annotation);
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Unhandled primitive type in array")) {
// box the array or convert to List before re-serializing
} else throw e;
} Prevention
- Store custom annotation values as boxed types or Lists, not raw primitive arrays
- Restrict custom keys to int[]/double[]/boolean[] if arrays are needed
- Test JSON output for every custom annotator key you add
- Prefer List<Long>/List<Float> over long[]/float[] in annotation values
When it happens
Trigger: Passing a map/annotation value that is a primitive array of a type other than int/double/boolean — e.g. a long[], short[], char[], byte[], or float[] — into JSONOutputter's write/output path.
Common situations: Custom Annotator keys storing long[] or float[] statistics arrays; utility code that boxes most values but stores raw primitive arrays of less-common types; passing NLP feature vectors stored as byte[] or short[].
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Unknown object to serialize
- RuntimeIOException wrapping IOException
- Failed to save classifier
- ERROR: Invalid dependency node line
- ERROR: Invalid format for dependency graph
AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10).
Data as JSON: /api/errors/511ef39577bdc488.
Report an issue: GitHub.
Appendix: source
Thrown at src/edu/stanford/nlp/pipeline/JSONOutputter.java:520
for (float elem : ((float[]) value)) {
lst.add(elem);
}
routeObject(indent, lst);
} else if (double.class.isAssignableFrom(componentType)) {
ArrayList<Double> lst = new ArrayList<>();
//noinspection Convert2streamapi
for (double elem : ((double[]) value)) {
lst.add(elem);
}
routeObject(indent, lst);
} else if (boolean.class.isAssignableFrom(componentType)) {
ArrayList<Boolean> lst = new ArrayList<>();
for (boolean elem : ((boolean[]) value)) {
lst.add(elem);
}
routeObject(indent, lst);
} else {
throw new IllegalStateException("Unhandled primitive type in array: " + componentType);
}
} else {
routeObject(indent, Arrays.asList((Object[]) value));
}
} else if (value instanceof Integer) {
writer.write(Integer.toString((Integer) value));
} else if (value instanceof Short) {
writer.write(Short.toString((Short) value));
} else if (value instanceof Byte) {
writer.write(Byte.toString((Byte) value));
} else if (value instanceof Long) {
writer.write(Long.toString((Long) value));
} else if (value instanceof Character) {
writer.write(Character.toString((Character) value));
} else if (value instanceof Float) {
// Use the US Locale so that we can conform with json output format
// The decimal separator is always supposed to be . for example
Locale locale = Locale.US;View on GitHub (pinned to 1b7edd19c4)