flowable/flowable-engine · critical · FlowableException
unknown variable type name
Error message
unknown variable type name
What it means
IbatisVariableTypeHandler.getResult(ResultSet, String) throws FlowableException when the TYPE_ column read from the database does not map to any registered VariableType (variableTypes.getVariableType returns null while typeName is non-null). This means the row references a variable type name unknown to the current engine configuration, so it cannot be deserialized safely.
Solutions
- Register the missing VariableType in the engine configuration (customPostVariableTypes / variableTypes) so getVariableType finds it
- Align Flowable versions across all nodes writing/reading the variable tables
- Inspect the offending row's TYPE_ column value and fix or migrate the data; also verify which query/column triggers it (getResult with columnName keeps returning null for NULL type names, but throws for unknown non-null names)
Example fix
// before (type missing at startup)
ProcessEngineConfiguration cfg = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("flowable.cfg.xml");
// after
cfg.setCustomPostVariableTypes(
Collections.singletonList(new MyCustomVariableType()));
// so IbatisVariableTypeHandler can resolve the row's TYPE_ name Defensive patterns
Strategy: try-catch
Validate before calling
String typeName = getTypeNameFromRow(row);
Set<String> known = engineConfiguration.getVariableTypes().getVariableTypes().stream()
.map(VariableType::getTypeName).collect(Collectors.toSet());
if (!known.contains(typeName)) {
throw new IllegalStateException("Unregistered variable type in DB: " + typeName);
} Try / catch
try {
VariableType type = typeHandler.getResult(rs, "TYPE_");
} catch (FlowableException e) {
if (e.getMessage().startsWith("unknown variable type name")) {
log.error("Variable row has unregistered type; register it or migrate data", e);
// skip row or fail the batch with a clear message
} else {
throw e;
}
} Prevention
- Register all custom VariableTypes in every engine configuration/cluster node
- Keep Flowable versions aligned across services sharing the same database
- Audit TYPE_ column values in ACT_RU_VARIABLE/ACT_HI_VARINST after upgrades or data imports
- Test variable round-trips (persist + query) after any type-registry change
When it happens
Trigger: Reading an ACT_RU_VARIABLE / ACT_HI_VARINST row whose TYPE_ value is not among registered types — e.g. the row was written by a different Flowable version or a custom variable type that is not registered in this deployment; a null-vs-typename mismatch in the custom-type registry.
Common situations: Rolling upgrades/downgrades where newer rows use types the older engine does not know; custom VariableType registered in one node of a cluster but not another; hand-edited or imported database data.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- version mismatch: library version is
- version mismatch: library version is
- Could not deserialize event to json
- Could not deserialize event to xml
- Could not deserialize job configuration
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/f2db327ea0813567.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/db/IbatisVariableTypeHandler.java:43
import org.flowable.variable.api.types.VariableTypes;
/**
* @author Dave Syer
*/
public class IbatisVariableTypeHandler implements TypeHandler<VariableType> {
protected VariableTypes variableTypes;
public IbatisVariableTypeHandler(VariableTypes variableTypes) {
this.variableTypes = variableTypes;
}
@Override
public VariableType getResult(ResultSet rs, String columnName) throws SQLException {
String typeName = rs.getString(columnName);
VariableType type = variableTypes.getVariableType(typeName);
if (type == null && typeName != null) {
throw new FlowableException("unknown variable type name " + typeName);
}
return type;
}
@Override
public VariableType getResult(CallableStatement cs, int columnIndex) throws SQLException {
String typeName = cs.getString(columnIndex);
VariableType type = variableTypes.getVariableType(typeName);
if (type == null) {
throw new FlowableException("unknown variable type name " + typeName);
}
return type;
}
@Override
public void setParameter(PreparedStatement ps, int i, VariableType parameter, JdbcType jdbcType) throws SQLException {
String typeName = parameter.getTypeName();
ps.setString(i, typeName);View on GitHub (pinned to d6d39ce1c6)