apache/beam · error · java.lang.IllegalArgumentException
Expected a Java primitive value but received
Error message
Expected a Java primitive value but received
What it means
JavaClassLookupTransformProvider decodes constructor arguments that arrive as Beam Rows back into Java objects. When the target constructor parameter is a primitive/wrapper/String, the decoder checks that the value supplied in the Row is also a primitive/wrapper/String. If the Row cell holds a different type (e.g. a Row or a List), it throws IllegalArgumentException.
Source
Thrown at sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/JavaClassLookupTransformProvider.java:338
@Nullable Row parameterRow = constructorRow.getRow(i);
Schema schema = getParameterSchema(parameterClass);
if (schema == null) {
throw new RuntimeException("Could not determine a schema for type " + parameterClass);
}
if (parameterRow != null && !parameterRow.getSchema().assignableTo(schema)) {
return false;
}
}
}
return true;
}
@SuppressWarnings("argument")
private @Nullable Object getDecodedValueFromRow(
Class<?> type, Object valueFromRow, @Nullable Type genericType) {
if (isPrimitiveOrWrapperOrString(type)) {
if (!isPrimitiveOrWrapperOrString(valueFromRow.getClass())) {
throw new IllegalArgumentException(
"Expected a Java primitive value but received " + valueFromRow);
}
return valueFromRow;
} else if (type.isArray()) {
Class<?> arrayComponentClass = type.getComponentType();
return getDecodedArrayValueFromRow(arrayComponentClass, valueFromRow);
} else if (Collection.class.isAssignableFrom(type)) {
List<Object> originalList = (List) valueFromRow;
List<Object> decodedList = new ArrayList<>();
for (Object obj : originalList) {
if (genericType instanceof ParameterizedType) {
Class<?> elementType =
(Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
decodedList.add(getDecodedValueFromRow(elementType, obj, null));
} else {
throw new RuntimeException("Could not determine the generic type of the list");
}
}View on GitHub (pinned to 12126d8942)
Solutions
- Fix the constructor schema so the field type matches the Java parameter type (primitive/wrapper/String vs ROW/ARRAY).
- Verify the parameter order/field mapping so primitive parameters line up with scalar Row fields.
- If the value is genuinely structured, change the constructor parameter to a schema-registered class instead of a primitive.
- Wrap getParameterValues/parameterValue in try-catch on IllegalArgumentException and fail the expansion request with a clear schema-mismatch message.
Example fix
// before: Row field is a nested Row but constructor expects long
Row.ofSchema(constructorSchema, Arrays.asList(Row.of(...), 42L))
// after: supply a scalar matching the constructor parameter type
Row.ofSchema(constructorSchema, Arrays.asList("name", 42L)) Defensive patterns
Strategy: validation
Validate before calling
boolean isScalar(Object v) { return v instanceof String || v instanceof Number || v instanceof Boolean || v instanceof Character; }
// verify each constructorSchema field is scalar before calling the expansion service Type guard
boolean matchesPrimitiveParam(Class<?> param, Object rowValue) { return (param.isPrimitive() || Number.class.isAssignableFrom(param) || param == String.class) && isScalar(rowValue); } Prevention
- Keep constructor schema field types aligned 1:1 with Java parameter types
- Validate the payload Row against the constructor schema before sending
- Avoid nesting Rows where constructors expect primitives
- Add expansion-service integration tests for each constructor signature
When it happens
Trigger: Calling the expansion service to construct a PTransform whose constructor takes a primitive/wrapper/String parameter, but the constructorSchema Row contains a non-primitive value (nested Row, List, or byte array) at that field position.
Common situations: Schema field typed as ROW or ARRAY in the payload while the Java constructor expects int/long/String; cross-language pipeline where the constructing SDK serializes a struct but the Java class expects a scalar; type drift after regenerating the constructor schema.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Unable to infer configuration row from configuration proto a
- Unable to provide coder for %s, this factory can only provid
- Provided coders for type arguments of %s contain incompatibi
- The input schema must have exactly one field of type byte.
- FieldType unexpected +fieldType.getTypeName()
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/cfe473b4c4612f6c.
Report an issue: GitHub.