apache/dolphinscheduler · error · ServiceException

DELETE_TENANT_BY_ID_FAIL_TENANTS

DELETE_TENANT_BY_ID_FAIL_TENANTS

Error message

DELETE_TENANT_BY_ID_FAIL_TENANTS: {tenantCount} tenants are using this queue, delete failed

What it means

QueueServiceImpl.deleteQueueById throws ServiceException(Status.DELETE_TENANT_BY_ID_FAIL_TENANTS, tenantCount) when tenants still reference the queue: tenantDao.queryTenantListByQueueId(queue.getId()) returns a non-empty list. The delete is a referential-integrity guard — queues in use by tenants cannot be removed. The message interpolates the number of blocking tenants.

Solutions

  1. Reassign the tenants to another queue (update each tenant's queue) via the tenant management API/UI, then retry the delete.
  2. List the blocking tenants (the error reports the count; query t_ds_tenant WHERE queue_id = <id>) and update them in bulk.
  3. If the queue truly should not be referenced, migrate the tenants' queue_id in the database during a maintenance window, then delete the queue.

Example fix

// before: delete while tenants still use queue
DELETE /dolphinscheduler/queues/7 -> DELETE_TENANT_BY_ID_FAIL_TENANTS (3 tenants)

// after: reassign tenants first
tenantService.updateTenant(loginUser, tenantId, ..., newQueueId); // for each of the 3 tenants
deleteQueueById(loginUser, 7) -> succeeds
Defensive patterns

Strategy: validation

Validate before calling

// check tenant references before deleting
List<Tenant> tenants = tenantDao.queryTenantListByQueueId(id);
if (!tenants.isEmpty()) {
    throw new IllegalStateException("Queue " + id + " still used by " + tenants.size() + " tenant(s)");
}

Try / catch

try {
    queueService.deleteQueueById(loginUser, id);
} catch (ServiceException e) {
    if (Status.DELETE_TENANT_BY_ID_FAIL_TENANTS.getCode() == e.getCode()) {
        // reassign tenants then retry
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling DELETE queue/{id} while one or more rows in t_ds_tenant have queue_id equal to the target queue's id; deleting a default/production YARN queue still assigned to tenants.

Common situations: Cleaning up old YARN queues that are still the default for tenant(s); importing tenant data pointing at the queue; multi-tenant environments where a queue remains assigned after team offboarding.

Related errors


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

Appendix: source

Thrown at dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/QueueServiceImpl.java:232

     * @throws Exception exception
     */
    @Override
    public void deleteQueueById(User loginUser, int id) throws Exception {

        if (!canOperatorPermissions(loginUser, null, AuthorizationType.TENANT, TENANT_DELETE)) {
            throw new ServiceException(Status.USER_NO_OPERATION_PERM);
        }

        Queue queue = queueDao.queryById(id);
        if (Objects.isNull(queue)) {
            log.error("Queue does not exist");
            throw new ServiceException(Status.QUEUE_NOT_EXIST);
        }

        List<Tenant> tenantList = tenantDao.queryTenantListByQueueId(queue.getId());
        if (CollectionUtils.isNotEmpty(tenantList)) {
            log.warn("Delete queue failed, because there are {} tenants using it.", tenantList.size());
            throw new ServiceException(Status.DELETE_TENANT_BY_ID_FAIL_TENANTS, tenantList.size());
        }

        List<User> userList = userDao.queryUserListByQueue(queue.getQueueName());
        if (CollectionUtils.isNotEmpty(userList)) {
            log.warn("Delete queue failed, because there are {} users using it.", userList.size());
            throw new ServiceException(Status.DELETE_QUEUE_BY_ID_FAIL_USERS, userList.size());
        }

        if (!queueDao.deleteById(id)) {
            throw new ServiceException(Status.DELETE_QUEUE_BY_ID_ERROR);
        }

    }

    /**
     * verify queue and queueName
     *
     * @param queue queue

View on GitHub (pinned to 02eac45a1b)