{"record":{"id":"702fbf0faad97e14","repo":"flowable/flowable-engine","slug":"unsupportedoperationexception","errorCode":null,"errorMessage":"UnsupportedOperationException","messagePattern":"UnsupportedOperationException","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/el/VariableContainerWrapper.java","lineNumber":55,"sourceCode":"\n    @Override\n    public boolean hasVariable(String variableName) {\n        return variables.containsKey(variableName);\n    }\n\n    @Override\n    public Object getVariable(String variableName) {\n        return variables.get(variableName);\n    }\n\n    @Override\n    public void setVariable(String variableName, Object variableValue) {\n        variables.put(variableName, variableValue);\n    }\n    \n    @Override\n    public void setTransientVariable(String variableName, Object variableValue) {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getInstanceId() {\n        return instanceId;\n    }\n\n    public void setInstanceId(String instanceId) {\n        this.instanceId = instanceId;\n    }\n\n    public String getScopeType() {\n        return scopeType;\n    }\n\n    public void setScopeType(String scopeType) {\n        this.scopeType = scopeType;\n    }\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/el/VariableContainerWrapper.java#L37-L73","documentation":"VariableContainerWrapper is a simple adapter wrapping a variables map, and its default implementation does not support transient variables — setTransientVariable always throws UnsupportedOperationException. Transient variables (not persisted, valid only for the current transaction/thread) require a VariableContainer that explicitly implements this method.","triggerScenarios":"Calling setTransientVariable(name, value) on a VariableContainerWrapper instance; passing a VariableContainerWrapper as the execution context to code (e.g. expression functions, delegates) that sets transient variables.","commonSituations":"Using VariableContainerWrapper to fake a DelegateExecution in unit tests or custom expression evaluation while the evaluated logic (e.g. a Flowable expression function or command) writes transient variables; upgrading Flowable where new internal code paths call setTransientVariable on containers that previously only needed setVariable.","solutions":["Do not set transient variables on VariableContainerWrapper; use a real DelegateExecution/VariableScope obtained from the engine.","Extend VariableContainerWrapper and override setTransientVariable if your use case needs in-memory transient storage.","In tests, use a mock of DelegateExecution/VariableContainer that implements setTransientVariable (e.g. store in a local map)."],"exampleFix":"// before\nVariableContainer c = new VariableContainerWrapper(map);\nc.setTransientVariable(\"loopCounter2\", 1); // throws\n\n// after\nVariableContainer c = new VariableContainerWrapper(map) {\n    @Override\n    public void setTransientVariable(String name, Object value) {\n        transientMap.put(name, value);\n    }\n};","handlingStrategy":"type-guard","validationCode":"if (container instanceof VariableContainerWrapper) {\n    throw new IllegalStateException(\"This code path sets transient variables; use a DelegateExecution-backed container\");\n}","typeGuard":"boolean supportsTransient(VariableContainer c) {\n    try { c.setTransientVariable(\"__probe__\", null); return true; }\n    catch (UnsupportedOperationException e) { return false; }\n}","tryCatchPattern":"try {\n    container.setTransientVariable(name, value);\n} catch (UnsupportedOperationException e) {\n    container.setVariable(name, value); // fallback to a regular variable if transient semantics are not required\n}","preventionTips":["Prefer a real DelegateExecution/VariableScope over VariableContainerWrapper when code sets transient variables.","In test doubles, implement setTransientVariable with an in-memory map.","Check Flowable upgrade notes: new internal paths may call setTransientVariable on custom containers."],"tags":["variables","transient","unsupported"],"backgroundTag":"unsupported-operation","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"}