{"record":{"id":"5cb09750941c6f30","repo":"flowable/flowable-engine","slug":"processdefinitionid-is-null-5cb097","errorCode":null,"errorMessage":"processDefinitionId is null","messagePattern":"processDefinitionId is null","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/GetProcessDefinitionHistoryLevelModelCmd.java","lineNumber":45,"sourceCode":"import org.flowable.engine.repository.ProcessDefinition;\n\n/**\n * @author Tijs Rademakers\n */\npublic class GetProcessDefinitionHistoryLevelModelCmd implements Command<HistoryLevel>, Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    protected String processDefinitionId;\n\n    public GetProcessDefinitionHistoryLevelModelCmd(String processDefinitionId) {\n        this.processDefinitionId = processDefinitionId;\n    }\n\n    @Override\n    public HistoryLevel execute(CommandContext commandContext) {\n        if (processDefinitionId == null) {\n            throw new FlowableIllegalArgumentException(\"processDefinitionId is null\");\n        }\n\n        HistoryLevel historyLevel = null;\n\n        ProcessDefinition processDefinition = CommandContextUtil.getProcessDefinitionEntityManager(commandContext).findById(processDefinitionId);\n\n        BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);\n\n        Process process = bpmnModel.getProcessById(processDefinition.getKey());\n        if (process.getExtensionElements().containsKey(\"historyLevel\")) {\n            ExtensionElement historyLevelElement = process.getExtensionElements().get(\"historyLevel\").iterator().next();\n            String historyLevelValue = historyLevelElement.getElementText();\n            if (StringUtils.isNotEmpty(historyLevelValue)) {\n                try {\n                    historyLevel = HistoryLevel.getHistoryLevelForKey(historyLevelValue);\n\n                } catch (Exception e) {\n                }","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/GetProcessDefinitionHistoryLevelModelCmd.java#L27-L63","documentation":"GetProcessDefinitionInfoCmd's sibling for history levels: execute throws FlowableIllegalArgumentException('processDefinitionId is null') when the constructor argument is null. The command resolves the history level defined in a process definition's model, which requires an id. Fail-fast argument validation before any lookup.","triggerScenarios":"Invoking the dynamic history-level lookup (e.g. via process engine configuration's getHistoryLevel(processDefinitionId)) with a null id — usually an unset variable or a lookup chain that returned null upstream.","commonSituations":"Configuration code that resolves the definition id conditionally and proceeds even when resolution failed; refactored code paths where the id assignment was removed; programmatic engine bootstrapping passing null defaults.","solutions":["Guard the id before invoking and throw/return with a clear message","Ensure the variable is populated from processEngineConfiguration or a deployment result before use","Check the upstream lookup (definition query) that produced the null id","Add an assertion/unit test covering the null-id path"],"exampleFix":"// before\nHistoryLevel level = engineConfig.getHistoryLevel(processDefinitionId); // id may be null\n// after\nif (processDefinitionId == null) {\n    throw new IllegalArgumentException(\"Cannot resolve history level: processDefinitionId is null\");\n}\nHistoryLevel level = engineConfig.getHistoryLevel(processDefinitionId);","handlingStrategy":"validation","validationCode":"if (processDefinitionId == null) {\n  throw new IllegalStateException(\"processDefinitionId must be resolved before reading history level\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  HistoryLevel level = getHistoryLevelForProcessDefinition(defId);\n} catch (FlowableIllegalArgumentException e) {\n  level = defaultHistoryLevel;\n}","preventionTips":["Never pass through ids from lookups that may return null without checking","Assert non-null id in the code path that builds the command","Cover the null-id branch in unit tests"],"tags":["flowable","null-argument","history-level","validation"],"backgroundTag":"null-argument","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"}