{"record":{"id":"3d94d7395055bb33","repo":"flowable/flowable-engine","slug":"the-variable-does-not-have-a-binary-data-stream-3d94d7","errorCode":null,"errorMessage":"The variable does not have a binary data stream.","messagePattern":"The variable does not have a binary data stream\\.","errorType":"http","errorClass":"FlowableObjectNotFoundException","httpStatus":404,"severity":"error","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/history/HistoricVariableInstanceDataResource.java","lineNumber":83,"sourceCode":"    @ResponseBody\n    public byte[] getVariableData(@ApiParam(name = \"varInstanceId\") @PathVariable(\"varInstanceId\") String varInstanceId, HttpServletResponse response) {\n        try {\n            byte[] result = null;\n            RestVariable variable = getVariableFromRequest(true, varInstanceId);\n            if (RestResponseFactory.BYTE_ARRAY_VARIABLE_TYPE.equals(variable.getType())) {\n                result = (byte[]) variable.getValue();\n                response.setContentType(\"application/octet-stream\");\n\n            } else if (RestResponseFactory.SERIALIZABLE_VARIABLE_TYPE.equals(variable.getType())) {\n                ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n                ObjectOutputStream outputStream = new ObjectOutputStream(buffer);\n                outputStream.writeObject(variable.getValue());\n                outputStream.close();\n                result = buffer.toByteArray();\n                response.setContentType(\"application/x-java-serialized-object\");\n\n            } else {\n                throw new FlowableObjectNotFoundException(\"The variable does not have a binary data stream.\", null);\n            }\n            return result;\n\n        } catch (IOException ioe) {\n            // Re-throw IOException\n            throw new FlowableException(\"Unexpected exception getting variable data\", ioe);\n        }\n    }\n\n    public RestVariable getVariableFromRequest(boolean includeBinary, String varInstanceId) {\n        HistoricVariableInstance varObject = historyService.createHistoricVariableInstanceQuery().id(varInstanceId).singleResult();\n\n        if (varObject == null) {\n            throw new FlowableObjectNotFoundException(\"Historic variable instance '\" + varInstanceId + \"' could not be found.\", VariableInstanceEntity.class);\n        } else {\n            \n            if (restApiInterceptor != null) {\n                restApiInterceptor.accessHistoryVariableInfoById(varObject);","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/history/HistoricVariableInstanceDataResource.java#L65-L101","documentation":"Thrown by the Flowable REST history API when a request asks for the binary data of a historic variable instance (by variable instance id) but the value is not a byte array that can be streamed. Only binary variables expose a /data endpoint; primitives and Strings are returned in the JSON representation instead. Raised as FlowableObjectNotFoundException since no binary stream exists for the variable.","triggerScenarios":"GET /history/historic-variable-instances/{varInstanceId}/data when the variable's type is not 'binary' (e.g. string, long, date, serializable handled via JSON), so getVariableData hits the else branch and throws.","commonSituations":"Generic download clients hitting /data for every variable id collected from the variables list endpoint; tests that assume all historic variables are attachments; migration scripts exporting variable blobs that include non-binary columns.","solutions":["Check the variable's type via GET /history/historic-variable-instances/{varInstanceId} and only request /data for type 'binary' (valueUrl present)","Read non-binary values directly from the variable JSON 'value' field","If the value should have been binary, fix the writer to store byte[] variables","Handle 404/FlowableObjectNotFoundException on the client by falling back to the JSON variable endpoint"],"exampleFix":"// before\nbyte[] raw = get('/history/historic-variable-instances/' + id + '/data')\n// after\nconst meta = await get('/history/historic-variable-instances/' + id)\nif (meta.data.valueUrl) {\n  return get(meta.data.valueUrl, { responseType: 'arraybuffer' })\n}\nreturn meta.data.value","handlingStrategy":"validation","validationCode":"const meta = await api.get(`/history/historic-variable-instances/${id}`);\nif (!meta.data.valueUrl) throw new SkipBinaryDownloadError(meta.data.type);","typeGuard":"function hasBinaryStream(meta) { return Boolean(meta && typeof meta.valueUrl === 'string'); }","tryCatchPattern":"try { return await api.get(`${baseUrl}/data`, {responseType:'arraybuffer'}); } catch (e) { if (e.response && e.response.status === 404) return (await api.get(baseUrl)).data.value; throw e; }","preventionTips":["Check type/valueUrl metadata before requesting /data","Treat /data as exclusive to byte[] variables","Fall back to the JSON variable endpoint for all other types"],"tags":["rest","flowable","binary-data","variable","history"],"backgroundTag":"resource-not-found","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}