{"record":{"id":"bb291233c25427f8","repo":"flowable/flowable-engine","slug":"unknown-variable-type-name-typename","errorCode":null,"errorMessage":"unknown variable type name <typeName>","messagePattern":"unknown variable type name <typeName>","errorType":"exception","errorClass":"ActivitiException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/db/IbatisVariableTypeHandler.java","lineNumber":40,"sourceCode":"import org.activiti.engine.impl.context.Context;\nimport org.apache.ibatis.type.JdbcType;\nimport org.apache.ibatis.type.TypeHandler;\nimport org.flowable.variable.api.types.VariableType;\nimport org.flowable.variable.api.types.VariableTypes;\n\n/**\n * @author Dave Syer\n */\npublic class IbatisVariableTypeHandler implements TypeHandler<VariableType> {\n\n    protected VariableTypes variableTypes;\n\n    @Override\n    public VariableType getResult(ResultSet rs, String columnName) throws SQLException {\n        String typeName = rs.getString(columnName);\n        VariableType type = getVariableTypes().getVariableType(typeName);\n        if (type == null && typeName != null) {\n            throw new ActivitiException(\"unknown variable type name \" + typeName);\n        }\n        return type;\n    }\n\n    @Override\n    public VariableType getResult(CallableStatement cs, int columnIndex) throws SQLException {\n        String typeName = cs.getString(columnIndex);\n        VariableType type = getVariableTypes().getVariableType(typeName);\n        if (type == null) {\n            throw new ActivitiException(\"unknown variable type name \" + typeName);\n        }\n        return type;\n    }\n\n    @Override\n    public void setParameter(PreparedStatement ps, int i, VariableType parameter, JdbcType jdbcType) throws SQLException {\n        String typeName = parameter.getTypeName();\n        ps.setString(i, typeName);","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/db/IbatisVariableTypeHandler.java#L22-L58","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nProcessEngineConfiguration cfg = ProcessEngineConfiguration\n    .createProcessEngineConfigurationFromResourceDefault();\n// after\ncfg.setCustomPostVariableTypes(new CustomStringType(\"custom-json\")); // re-add handler for stored TYPE_ 'custom-json'","handlingStrategy":"try-catch","validationCode":"Set<String> known = variableTypes.keySet == null ? null : null; // check via:\n// SELECT DISTINCT TYPE_ FROM ACT_RU_VARIABLE\n// and confirm each value resolves through engineConfig.getVariableTypes().getVariableType(type) != null","typeGuard":"boolean isKnownVariableType(ProcessEngineConfiguration cfg, String typeName) {\n  return typeName != null && cfg.getVariableTypes().getVariableType(typeName) != null;\n}","tryCatchPattern":"try {\n  Map<String, Object> vars = taskService.getVariables(taskId);\n} catch (ActivitiException e) {\n  if (e.getMessage().startsWith(\"unknown variable type name\")) {\n    logger.error(\"Variable row references an unregistered type; register the VariableType or migrate rows\", e);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["database","variables","deserialization","type"],"backgroundTag":"type-mismatch","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}