apache/dolphinscheduler · error · ServiceException

50038

50038

Error message

update task definition error

What it means

ServiceException(Status.UPDATE_TASK_DEFINITION_ERROR, 50038) signals an inconsistent update in releaseTaskDefinition: `updateSuccess` (taskDefinitionDao.updateById) and `updateLog == 1` (taskDefinitionLogMapper.updateById) disagree, so the definition and its version log are out of sync. The library throws instead of leaving partial state.

Source

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

                    try {
                        permissionCheck.checkPermission();
                    } catch (Exception e) {
                        log.error("Resources permission check error, resourceIds:{}.", resourceIds, e);
                        throw new ServiceException(Status.RESOURCE_NOT_EXIST_OR_NO_PERMISSION);
                    }
                }
                taskDefinition.setFlag(Flag.YES);
                taskDefinitionLog.setFlag(Flag.YES);
                break;
            default:
                log.warn("Parameter releaseState is invalid.");
                throw new ServiceException(Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.RELEASE_STATE);
        }
        boolean updateSuccess = taskDefinitionDao.updateById(taskDefinition);
        int updateLog = taskDefinitionLogMapper.updateById(taskDefinitionLog);
        if (updateSuccess != (updateLog == 1)) {
            log.error("Update taskDefinition state or taskDefinitionLog state error, taskDefinitionCode:{}.", code);
            throw new ServiceException(Status.UPDATE_TASK_DEFINITION_ERROR);
        }
        log.info("Update taskDefinition state or taskDefinitionLog state to complete, taskDefinitionCode:{}.",
                code);
    }

    @Override
    public void deleteTaskByWorkflowDefinitionCode(long workflowDefinitionCode, int workflowDefinitionVersion) {
        List<WorkflowTaskRelation> workflowTaskRelations = workflowTaskRelationService
                .queryByWorkflowDefinitionCode(workflowDefinitionCode, workflowDefinitionVersion);
        if (CollectionUtils.isEmpty(workflowTaskRelations)) {
            return;
        }
        // delete task definition
        Set<Long> needToDeleteTaskDefinitionCodes = new HashSet<>();
        for (WorkflowTaskRelation workflowTaskRelation : workflowTaskRelations) {
            needToDeleteTaskDefinitionCodes.add(workflowTaskRelation.getPreTaskCode());
            needToDeleteTaskDefinitionCodes.add(workflowTaskRelation.getPostTaskCode());
        }

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Verify both T_DS_TASK_DEFINITION and T_DS_TASK_DEFINITION_LOG rows exist with matching code+version, then retry the release
  2. Wrap the two updates in a single transaction so they succeed or fail together
  3. Check for concurrent jobs/locks touching the task definition and retry when idle
  4. Inspect the TaskDefinitionLog id field — re-query the log row before updating instead of reusing a stale entity

Example fix

// before: two independent updates, mismatch possible
boolean updateSuccess = taskDefinitionDao.updateById(taskDefinition);
int updateLog = taskDefinitionLogMapper.updateById(taskDefinitionLog);
// after: make them transactional and re-check row counts together
@Transactional
void release(...) {
    if (!(taskDefinitionDao.updateById(taskDefinition) && taskDefinitionLogMapper.updateById(taskDefinitionLog) == 1)) {
        throw new ServiceException(Status.UPDATE_TASK_DEFINITION_ERROR);
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-check both rows exist and are current
if (taskDefinitionDao.queryByCode(code) == null ||
    taskDefinitionLogMapper.queryByDefinitionCodeAndVersion(code, version) == null) {
    throw new IllegalStateException("definition/log rows out of sync before update");
}

Type guard

boolean rowsInSync(long code, int version) {
    TaskDefinition td = taskDefinitionDao.queryByCode(code);
    return td != null && taskDefinitionLogMapper.queryByDefinitionCodeAndVersion(code, td.getVersion()) != null;
}

Try / catch

try {
    service.releaseTaskDefinition(loginUser, projectCode, code, state);
} catch (ServiceException e) {
    if (e.getCode() == Status.UPDATE_TASK_DEFINITION_ERROR.getCode()) {
        // verify row states, resolve contention, then retry once
    }
    throw e;
}

Prevention

When it happens

Trigger: updateById on T_DS_TASK_DEFINITION succeeds but the log update affects 0 rows (or vice versa) during releaseTaskDefinition — e.g., the TaskDefinitionLog entity is stale so its id no longer matches a row.

Common situations: Concurrent modification deleting/updating the log row between query and update; log row missing an id after manual insertion; DB replication lag or deadlock causing one update to fail; transaction isolation issues.

Related errors


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