apache/dolphinscheduler · error · ServiceException

50041

50041

Error message

delete task definition version error

What it means

Thrown when the delete of a task definition version from t_ds_task_definition_log affects zero rows (taskDefinitionLogMapper.deleteByCodeAndVersion returned <= 0). It means the requested (code, version) pair does not exist in the version-history table, so nothing was deleted.

Source

Thrown at dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskDefinitionServiceImpl.java:286

        // check if user have write perm for project
        projectService.checkHasProjectWritePermissionThrowException(loginUser, project);

        TaskDefinition taskDefinition = taskDefinitionDao.queryByCode(taskCode);
        if (taskDefinition == null || projectCode != taskDefinition.getProjectCode()) {
            log.error("Task definition does not exist, taskDefinitionCode:{}.", taskCode);
            throw new ServiceException(Status.TASK_DEFINE_NOT_EXIST, String.valueOf(taskCode));
        }
        if (taskDefinition.getVersion() == version) {
            log.warn(
                    "Task definition can not be deleted due to version is being used, projectCode:{}, taskDefinitionCode:{}, version:{}.",
                    projectCode, taskCode, version);
            throw new ServiceException(Status.MAIN_TABLE_USING_VERSION);
        }
        int delete = taskDefinitionLogMapper.deleteByCodeAndVersion(taskCode, version);
        if (delete <= 0) {
            log.error("Task definition version delete error, projectCode:{}, taskDefinitionCode:{}, version:{}.",
                    projectCode, taskCode, version);
            throw new ServiceException(Status.DELETE_TASK_DEFINITION_VERSION_ERROR);
        }
        log.info(
                "Task definition version delete complete, projectCode:{}, taskDefinitionCode:{}, version:{}.",
                projectCode, taskCode, version);
    }

    @Override
    public TaskDefinitionVO queryTaskDefinitionDetail(User loginUser, long projectCode, long taskCode) {
        Project project = projectDao.queryByCode(projectCode);
        // check user access for project
        projectService.checkProjectAndAuthThrowException(loginUser, project, TASK_DEFINITION);

        TaskDefinition taskDefinition = taskDefinitionDao.queryByCode(taskCode);
        if (taskDefinition == null || projectCode != taskDefinition.getProjectCode()) {
            log.error("Task definition does not exist, taskDefinitionCode:{}.", taskCode);
            throw new ServiceException(Status.TASK_DEFINE_NOT_EXIST, String.valueOf(taskCode));
        }
        List<WorkflowTaskRelation> taskRelationList = workflowTaskRelationDao

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Verify the version exists before deleting: taskDefinitionLogMapper.queryByDefinitionCodeAndVersion(code, version) != null.
  2. Make cleanup scripts idempotent: treat zero-row deletes as success rather than retrying.
  3. Catch ServiceException code 50041 and log the (code, version) pair for diagnosis instead of failing the whole batch.

Example fix

// before
taskDefinitionService.deleteByCodeAndVersion(loginUser, projectCode, code, version); // throws if rows==0
// after
if (taskDefinitionLogMapper.queryByDefinitionCodeAndVersion(code, version) != null) {
    taskDefinitionService.deleteByCodeAndVersion(loginUser, projectCode, code, version);
}
Defensive patterns

Strategy: validation

Validate before calling

TaskDefinitionLog log = taskDefinitionLogMapper.queryByDefinitionCodeAndVersion(code, version);
if (log == null) { throw new IllegalStateException("version " + version + " not in history"); }

Type guard

boolean versionExists(TaskDefinitionLog l) {
    return l != null && l.getVersion() > 0;
}

Try / catch

try {
    taskDefinitionService.deleteByCodeAndVersion(loginUser, projectCode, code, version);
} catch (ServiceException e) {
    if (e.getCode() == 50041) { /* already deleted: treat as success in idempotent scripts */ }
    else { throw e; }
}

Prevention

When it happens

Trigger: Calling deleteByCodeAndVersion with a version number that was never persisted to the log table (typo, already deleted, version beyond history), while the version check against the master table passed.

Common situations: Double-deleting the same version from concurrent scripts or retries; off-by-one when enumerating versions; environments where history was purged externally.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/ea14c75f4934495d. Report an issue: GitHub.