{"record":{"id":"048a61a5d3f9f943","repo":"apache/dolphinscheduler","slug":"delete-workflow-define-by-code-error","errorCode":"DELETE_WORKFLOW_DEFINE_BY_CODE_ERROR","errorMessage":"DELETE_WORKFLOW_DEFINE_BY_CODE_ERROR: delete workflow definition by code error","messagePattern":"DELETE_WORKFLOW_DEFINE_BY_CODE_ERROR: delete workflow definition by code error","errorType":"error_code","errorClass":"ServiceException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java","lineNumber":1752,"sourceCode":"            throw new ServiceException(Status.WORKFLOW_DEFINITION_NOT_EXIST, code);\n        }\n        if (workflowDefinition.getVersion() == version) {\n            log.warn(\"This version: {} of workflow: {} is the main version cannot delete by version\", code, version);\n            throw new ServiceException(Status.MAIN_TABLE_USING_VERSION);\n        }\n        // check whether there exist running workflow instance under the workflow definition\n        List<WorkflowInstanceSummaryDto> workflowInstances = workflowInstanceService.queryByWorkflowCodeVersionStatus(\n                code,\n                version,\n                WorkflowExecutionStatus.NOT_TERMINAL_STATES);\n        if (CollectionUtils.isNotEmpty(workflowInstances)) {\n            throw new ServiceException(Status.DELETE_WORKFLOW_DEFINITION_EXECUTING_FAIL, workflowInstances.size());\n        }\n\n        int deleteLog = workflowDefinitionLogMapper.deleteByWorkflowDefinitionCodeAndVersion(code, version);\n        int deleteRelationLog = workflowTaskRelationLogMapper.deleteByCode(code, version);\n        if (deleteLog == 0 || deleteRelationLog == 0) {\n            throw new ServiceException(Status.DELETE_WORKFLOW_DEFINE_BY_CODE_ERROR);\n        }\n        log.info(\"Delete version: {} of workflow: {}, projectCode: {}\", version, code, projectCode);\n\n    }\n\n    @Transactional\n    @Override\n    public void onlineWorkflowDefinition(User loginUser, Long projectCode, Long workflowDefinitionCode) {\n        projectService.checkHasProjectWritePermissionThrowException(loginUser, projectCode);\n\n        WorkflowDefinition workflowDefinition = workflowDefinitionDao.queryByCode(workflowDefinitionCode)\n                .orElseThrow(() -> new ServiceException(Status.WORKFLOW_DEFINITION_NOT_EXIST, workflowDefinitionCode));\n        if (projectCode != workflowDefinition.getProjectCode()) {\n            throw new ServiceException(Status.WORKFLOW_DEFINITION_NOT_EXIST, workflowDefinitionCode);\n        }\n\n        if (ReleaseState.ONLINE.equals(workflowDefinition.getReleaseState())) {\n            // do nothing if the workflow is already online","sourceCodeStart":1734,"sourceCodeEnd":1770,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java#L1734-L1770","documentation":"Thrown when the actual DELETE of a workflow definition version from the log tables affected zero rows — either workflowDefinitionLogMapper.deleteByWorkflowDefinitionCodeAndVersion or workflowTaskRelationLogMapper.deleteByCode returned 0. It indicates the version rows expected to exist in the history tables are missing, so the delete is treated as failed rather than silently succeeding.","triggerScenarios":"deleteWorkflowDefinitionVersion on a (code, version) pair absent from t_ds_workflow_definition_log or t_ds_workflow_task_relation_log — e.g., the version was already deleted, or was never logged due to an interrupted save.","commonSituations":"Double-delete races where two cleanup scripts target the same version concurrently; databases restored from partial backups missing log rows; manually purged history tables.","solutions":["Verify the (code, version) rows exist in t_ds_workflow_definition_log and t_ds_workflow_task_relation_log before deleting.","Make cleanup scripts idempotent: treat 'already gone' as success by checking existence first.","Serialize cleanup jobs (lock or leader election) to avoid concurrent double-deletes.","If rows are genuinely missing due to data corruption, re-import or repair the definition history."],"exampleFix":"// before: unconditional delete, throws if 0 rows\nworkflowDefinitionLogMapper.deleteByWorkflowDefinitionCodeAndVersion(code, version);\n// after: check existence first\nif (workflowDefinitionLogMapper.queryByWorkflowDefinitionCodeAndVersion(code, version) != null) {\n    workflowDefinitionLogMapper.deleteByWorkflowDefinitionCodeAndVersion(code, version);\n}","handlingStrategy":"validation","validationCode":"boolean versionExists =\n    workflowDefinitionLogMapper.queryByWorkflowDefinitionCodeAndVersion(code, version) != null\n    && !workflowTaskRelationLogMapper.queryByCode(code, version).isEmpty();\nif (!versionExists) {\n    return; // treat as already deleted (idempotent)\n}","typeGuard":"boolean rowsPresent(int deleteLog, int deleteRelationLog) {\n    return deleteLog > 0 && deleteRelationLog > 0;\n}","tryCatchPattern":"try {\n    service.deleteWorkflowDefinitionVersion(user, projectCode, code, version);\n} catch (ServiceException e) {\n    if (e.getCode() == Status.DELETE_WORKFLOW_DEFINE_BY_CODE_ERROR.getCode()) {\n        // rows already gone or partial delete; verify state and continue idempotently\n    } else throw e;\n}","preventionTips":["Run only one cleanup job at a time to avoid double-deletes.","Make delete scripts idempotent by checking row existence first.","Verify backups/restores include the *_log tables, not just the main table."],"tags":["workflow-definition","delete-failed","database","idempotency"],"backgroundTag":"database-write-failed","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}