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

  1. Guard for null before storing: if the entity is null, either skip the setVariable call or pass a type that handles null
  2. Use a type-agnostic setVariable so Flowable's NullVariableType handles null
  3. 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

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


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)