flowable/flowable-engine · error · ActivitiException
unknown variable type name
Error message
unknown variable type name <typeName>
What it means
IbatisVariableTypeHandler.getResult reads the TYPE_ column of a variable row and looks it up among registered VariableTypes. When the stored type name is non-null but no registered type matches, Flowable throws because it cannot deserialize the variable value. This typically means the row was written by an engine with different variable type handlers.
Solutions
- Re-register the missing VariableType in the process engine configuration (customTypes / preBPMNParseHandlers on VariableTypes)
- Identify the offending TYPE_ value via SELECT DISTINCT TYPE_ on the variable tables and map it to a supported type
- Restore the engine version that wrote the data, or migrate the variable rows to supported types
- If the variable is obsolete, clean up the rows in a controlled migration
Example fix
// before
ProcessEngineConfiguration cfg = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResourceDefault();
// after
cfg.setCustomPostVariableTypes(new CustomStringType("custom-json")); // re-add handler for stored TYPE_ 'custom-json' Defensive patterns
Strategy: try-catch
Validate before calling
Set<String> known = variableTypes.keySet == null ? null : null; // check via: // SELECT DISTINCT TYPE_ FROM ACT_RU_VARIABLE // and confirm each value resolves through engineConfig.getVariableTypes().getVariableType(type) != null
Type guard
boolean isKnownVariableType(ProcessEngineConfiguration cfg, String typeName) {
return typeName != null && cfg.getVariableTypes().getVariableType(typeName) != null;
} Try / catch
try {
Map<String, Object> vars = taskService.getVariables(taskId);
} catch (ActivitiException e) {
if (e.getMessage().startsWith("unknown variable type name")) {
logger.error("Variable row references an unregistered type; register the VariableType or migrate rows", e);
}
throw e;
} Prevention
- Register all custom VariableTypes in the engine configuration before startup
- Never remove a VariableType while rows referencing it exist
- Test engine upgrades against a copy of production variable data
When it happens
Trigger: Reading process/execution/task variables via the API or engine queries when a row in ACT_RU_VARIABLE / ACT_HI_VARINSTALL has a TYPE_ value not present in the current VariableTypes registry (e.g. custom type removed, engine downgraded, JSON type missing).
Common situations: Upgrading/downgrading engines with different variable types, removing a custom VariableType from the config while old rows still reference it, or history rows written by a newer engine version.
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
- unknown variable type name
- Couldn't deserialize object in variable
- Deserialized value is not an array of ID's
- Entity does not exist
- Error converting request body to RestVariable instance
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/bb291233c25427f8.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/db/IbatisVariableTypeHandler.java:40
import org.activiti.engine.impl.context.Context;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.flowable.variable.api.types.VariableType;
import org.flowable.variable.api.types.VariableTypes;
/**
* @author Dave Syer
*/
public class IbatisVariableTypeHandler implements TypeHandler<VariableType> {
protected VariableTypes variableTypes;
@Override
public VariableType getResult(ResultSet rs, String columnName) throws SQLException {
String typeName = rs.getString(columnName);
VariableType type = getVariableTypes().getVariableType(typeName);
if (type == null && typeName != null) {
throw new ActivitiException("unknown variable type name " + typeName);
}
return type;
}
@Override
public VariableType getResult(CallableStatement cs, int columnIndex) throws SQLException {
String typeName = cs.getString(columnIndex);
VariableType type = getVariableTypes().getVariableType(typeName);
if (type == null) {
throw new ActivitiException("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)