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
- Verify both T_DS_TASK_DEFINITION and T_DS_TASK_DEFINITION_LOG rows exist with matching code+version, then retry the release
- Wrap the two updates in a single transaction so they succeed or fail together
- Check for concurrent jobs/locks touching the task definition and retry when idle
- 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
- Run the two updates in one transaction to avoid partial state
- Avoid concurrent edits to the same task definition (use UI locks/serialization)
- Re-query the log row immediately before updating instead of caching entities
- Monitor for DB deadlocks/replication lag on the definition tables
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.