flowable/flowable-engine · error · FlowableIllegalArgumentException
null value cannot be saved
Error message
null value cannot be saved
What it means
JPAEntityMappings.getJPAClassString maps a variable value to its entity class name for persistence. A null value cannot be mapped, so it throws FlowableIllegalArgumentException('null value cannot be saved').
Solutions
- Guard for null before storing: if the entity is null, either skip the setVariable call or pass a type that handles null
- Use a type-agnostic setVariable so Flowable's NullVariableType handles null
- Ensure upstream code (forms, services) never yields null for required entity variables
Example fix
// before
Customer c = customerDao.find(id);
runtimeService.setVariable(executionId, "customer", c); // c may be null
// after
Customer c = customerDao.find(id);
if (c != null) {
runtimeService.setVariable(executionId, "customer", c);
} else {
runtimeService.setVariable(executionId, "customer", null); // handled by NullVariableType
} Defensive patterns
Strategy: validation
Validate before calling
if (value == null) {
// don't route null through JPA variable type
runtimeService.setVariable(executionId, "customer", null);
} else {
runtimeService.setVariable(executionId, "customer", value);
} Type guard
boolean isNonNullEntity(Object v) { return v != null; } Prevention
- Null-check DAO results before storing as variables
- Let Flowable pick NullVariableType automatically for null values (no explicit JPA type)
- Make entity variables optional-aware in forms and service tasks
When it happens
Trigger: Calling getJPAClassString(null), typically via setValue on a JPA variable type path that doesn't pre-filter nulls, e.g. saving a variable whose value is null through a code path expecting an entity.
Common situations: Passing null entities from process/service code into setVariable with an explicitly chosen JPA type; form/task data binding supplying null; DAO returning null and result being stored directly.
Related errors
- Booleans and null cannot be used in 'greater than or equal'…
- Booleans and null cannot be used in 'less than or equal'…
- deploymentId is null
- entityManagerFactory is null
- A channel key detection value is required for the channel…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/c854f9748f509665.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/types/JPAEntityMappings.java:69
}
public EntityMetaData getEntityMetaData(Class<?> clazz) {
EntityMetaData metaData = classMetaDatamap.get(clazz.getName());
if (metaData == null) {
// Class not present in meta-data map, create metaData for it and add
metaData = scanClass(clazz);
classMetaDatamap.put(clazz.getName(), metaData);
}
return metaData;
}
private EntityMetaData scanClass(Class<?> clazz) {
return enitityScanner.scanClass(clazz);
}
public String getJPAClassString(Object value) {
if (value == null) {
throw new FlowableIllegalArgumentException("null value cannot be saved");
}
EntityMetaData metaData = getEntityMetaData(value.getClass());
if (!metaData.isJPAEntity()) {
throw new FlowableIllegalArgumentException("Object is not a JPA Entity: class='" + value.getClass() + "', " + value);
}
// Extract the class from the Entity instance
return metaData.getEntityClass().getName();
}
public String getJPAIdString(Object value) {
EntityMetaData metaData = getEntityMetaData(value.getClass());
if (!metaData.isJPAEntity()) {
throw new FlowableIllegalArgumentException("Object is not a JPA Entity: class='" + value.getClass() + "', " + value);
}
Object idValue = getIdValue(value, metaData);
return getIdString(idValue);View on GitHub (pinned to d6d39ce1c6)