oracle/graal · error · RuntimeException
boxed object: {} is not a primitive
Error message
boxed object: {} is not a primitive What it means
Thrown by TagConstants.getTagFromPrimitive(Object boxed) when the argument is none of the eight primitive wrappers (Integer, Float, Double, Long, Byte, Short, Character, Boolean). The JDWP protocol assigns a one-byte tag to every value it serializes, and this helper maps a boxed primitive to its tag; a non-primitive object has no primitive tag, so the mapping is a caller bug, not an environmental condition.
Source
Thrown at espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/TagConstants.java:84
if (boxed instanceof Double) {
return DOUBLE;
}
if (boxed instanceof Long) {
return LONG;
}
if (boxed instanceof Byte) {
return BYTE;
}
if (boxed instanceof Short) {
return SHORT;
}
if (boxed instanceof Character) {
return CHAR;
}
if (boxed instanceof Boolean) {
return BOOLEAN;
}
throw new RuntimeException("boxed object: " + boxed.getClass() + " is not a primitive");
}
public static byte toTagConstant(JavaKind kind) {
switch (kind) {
case Boolean:
return TagConstants.BOOLEAN;
case Byte:
return TagConstants.BYTE;
case Short:
return TagConstants.SHORT;
case Char:
return TagConstants.CHAR;
case Int:
return TagConstants.INT;
case Float:
return TagConstants.FLOAT;
case Long:
return TagConstants.LONG;View on GitHub (pinned to a66e9ccd1d)
Solutions
- Branch on the value first: use getTagFromPrimitive only when value instanceof Number, Character, or Boolean
- Handle reference values with the OBJECT/STRING/ARRAY/THREAD tags before calling the primitive mapper
- Null-check the boxed value before mapping
Example fix
// before
byte tag = TagConstants.getTagFromPrimitive(value);
// after
byte tag;
if (value == null || !(value instanceof Number || value instanceof Character || value instanceof Boolean)) {
tag = TagConstants.OBJECT;
} else {
tag = TagConstants.getTagFromPrimitive(value);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!(boxed instanceof Number || boxed instanceof Character || boxed instanceof Boolean)) {
// route to reference-value tag handling instead
} Type guard
static boolean isBoxedPrimitive(Object v) {
return v instanceof Number || v instanceof Character || v instanceof Boolean;
} Try / catch
catch (RuntimeException e) when message contains 'not a primitive': map value to TagConstants.OBJECT and continue serialization.
Prevention
- Always branch primitive vs reference before tag mapping
- Null-check values before calling getTagFromPrimitive
When it happens
Trigger: A JDWP back-end code path (e.g. building a Value packet for a watched field or method return) calls getTagFromPrimitive on a value that is actually a String, an array, null, or a plain object; null fails earlier at boxed.getClass() with an NPE if not guarded.
Common situations: Debugger-plugin code in Espresso that assumes a static field type guarantees a primitive value (obfuscated/recycled classes where the declared type lies), or new JDWP command implementations routing reference values through the primitive mapper.
Related errors
- Invalid JDWP option value: {key} can be only 'y' or 'n'.
- JDWP options must be a comma separated list of key=value pai
- Invalid JDWP option, address: {value}. Must be in the 0 - 65
- Invalid JDWP option, address: {value}. Port is not a number.
- Invalid transport {value}. Espresso only supports dt_socket
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/e985fc6a538ee149.
Report an issue: GitHub.