{"record":{"id":"816a65386ed108bf","repo":"flowable/flowable-engine","slug":"couldn-t-deserialize-object-in-variable-name","errorCode":null,"errorMessage":"Couldn't deserialize object in variable '${name}'","messagePattern":"Couldn't deserialize object in variable '(.+?)'","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/types/SerializableType.java","lineNumber":161,"sourceCode":"            oos = createObjectOutputStream(baos);\n            oos.writeObject(value);\n        } catch (Exception e) {\n            throw new FlowableException(\"Couldn't serialize value '\" + value + \"' in variable '\" + valueFields.getName() + \"'\", e);\n        } finally {\n            IoUtil.closeSilently(oos);\n        }\n        return baos.toByteArray();\n    }\n\n    public Object deserialize(byte[] bytes, ValueFields valueFields) {\n        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\n        try {\n            ObjectInputStream ois = createObjectInputStream(bais);\n            Object deserializedObject = ois.readObject();\n\n            return deserializedObject;\n        } catch (Exception e) {\n            throw new FlowableException(\"Couldn't deserialize object in variable '\" + valueFields.getName() + \"'\", e);\n        } finally {\n            IoUtil.closeSilently(bais);\n        }\n    }\n    \n    protected VariableServiceConfiguration getVariableServiceConfiguration(ValueFields valueFields) {\n        String engineType = getEngineType(valueFields.getScopeType());\n        Map<String, AbstractEngineConfiguration> engineConfigurationMap = Context.getCommandContext().getEngineConfigurations();\n        AbstractEngineConfiguration engineConfiguration = engineConfigurationMap.get(engineType);\n        if (engineConfiguration == null) {\n            for (AbstractEngineConfiguration possibleEngineConfiguration : engineConfigurationMap.values()) {\n                if (possibleEngineConfiguration instanceof HasVariableServiceConfiguration) {\n                    engineConfiguration = possibleEngineConfiguration;\n                }\n            }\n        }\n        \n        if (engineConfiguration == null) {","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/types/SerializableType.java#L143-L179","documentation":"SerializableType rehydrates a persisted variable by reading bytes back through ObjectInputStream. This FlowableException wraps any failure in readObject — typically ClassNotFoundException (the class changed or is missing at deserialization time) or stream corruption (InvalidClassException from serialVersionUID mismatch).","triggerScenarios":"Reading a serialized variable from the database when the value's class is not on the classpath of the node deserializing, when the class's serialVersionUID changed between write and read, or when the stored byte array is corrupted/truncated.","commonSituations":"Rolling deployments where the variable class was renamed/refactored without a fixed serialVersionUID; cluster nodes with different versions of the application jar; restoring a DB dump into an app missing the domain classes.","solutions":["Ensure the class stored in the variable exists with an identical serialVersionUID (declare an explicit private static final long serialVersionUID) on all nodes that read the variable","Check the wrapped cause: ClassNotFoundException means missing class/jar on this node — add the dependency","Avoid version-sensitive serialized objects in variables: store JSON/plain values or upgrade via a data migration","If bytes are corrupted, delete/reinitialize the variable rather than retrying deserialization"],"exampleFix":"// before\npublic class CustomerDTO { private String name; }\n// after\npublic class CustomerDTO implements java.io.Serializable {\n    private static final long serialVersionUID = 1L;\n    private String name;\n}","handlingStrategy":"try-catch","validationCode":"// Ensure the class can round-trip before relying on serialized variables\nObject roundTrip = new ObjectInputStream(\n    new ByteArrayInputStream(new ObjectOutputStream(new ByteArrayOutputStream()) {{ writeObject(dto); flush(); }}.toByteArray())).readObject();","typeGuard":"if (!dto.getClass().getPackage().getName().startsWith(\"com.myapp\")) {\n    throw new IllegalStateException(\"Refusing to store third-party class in serialized variable\");\n}","tryCatchPattern":"try {\n    Object value = execution.getVariable(name);\n} catch (FlowableException e) {\n    if (e.getCause() instanceof ClassNotFoundException) {\n        log.error(\"Missing class for serialized variable {}: {}\", name, e.getCause().getMessage());\n    } else if (e.getCause() instanceof InvalidClassException) {\n        log.error(\"serialVersionUID mismatch for variable {}: {}\", name, e.getCause().getMessage());\n    }\n    throw e;\n}","preventionTips":["Always declare an explicit serialVersionUID on classes stored in variables","Keep the domain-model jars identical across all cluster nodes","Prefer JSON/plain values over Java serialization for variables that must survive refactors","Test deserialization of persisted variables after every model change"],"tags":["deserialization","java","variables"],"backgroundTag":"json-unmarshal-failed","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"}