apache/dolphinscheduler · error · ServiceException
10009
10009
Error message
os tenant code {tenantCode} already exists What it means
Status.OS_TENANT_CODE_EXIST from createTenantValid: a tenant with the given tenantCode already exists in t_ds_tenant (checkTenantExists returns true). Tenant codes are unique keys mapping to OS users, so duplicates are rejected.
Source
Thrown at dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TenantServiceImpl.java:94
private UserDao userDao;
@Autowired
private QueueService queueService;
/**
* Check the tenant new object valid or not
*
* @param tenant The tenant object want to create
*/
private void createTenantValid(Tenant tenant) throws ServiceException {
if (StringUtils.isEmpty(tenant.getTenantCode())) {
throw new ServiceException(Status.REQUEST_PARAMS_NOT_VALID_ERROR, tenant.getTenantCode());
} else if (StringUtils.length(tenant.getTenantCode()) > TENANT_FULL_NAME_MAX_LENGTH) {
throw new ServiceException(Status.TENANT_FULL_NAME_TOO_LONG_ERROR);
} else if (!RegexUtils.isValidLinuxUserName(tenant.getTenantCode())) {
throw new ServiceException(Status.CHECK_OS_TENANT_CODE_ERROR);
} else if (checkTenantExists(tenant.getTenantCode())) {
throw new ServiceException(Status.OS_TENANT_CODE_EXIST, tenant.getTenantCode());
}
}
/**
* Check tenant update object valid or not
*
* @param existsTenant The exists queue object
* @param updateTenant The queue object want to update
*/
private void updateTenantValid(Tenant existsTenant, Tenant updateTenant) throws ServiceException {
// Check the exists tenant
if (Objects.isNull(existsTenant)) {
log.error("Tenant does not exist.");
throw new ServiceException(Status.TENANT_NOT_EXIST);
}
// Check the update tenant parameters
else if (StringUtils.isEmpty(updateTenant.getTenantCode())) {
throw new ServiceException(Status.REQUEST_PARAMS_NOT_VALID_ERROR, updateTenant.getTenantCode());View on GitHub (pinned to 02eac45a1b)
Solutions
- Query the tenant list first and reuse the existing tenant instead of creating a new one.
- Make scripts idempotent: check existence (or catch this error) before create.
- Serialize tenant provisioning (single sync job, distributed lock) to avoid the create race.
- If the old tenant is stale, delete it first via the tenant management API, then recreate.
Example fix
// before
tenantService.createTenant(loginUser, "ds_tenant", "desc", 1); // throws if exists
// after
if (!tenantService.checkTenantExists("ds_tenant")) {
tenantService.createTenant(loginUser, "ds_tenant", "desc", 1);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (tenantService.checkTenantExists(tenantCode)) {
return; // tenant already provisioned
} Try / catch
try {
tenantService.createTenant(loginUser, tenantCode, desc, queueId);
} catch (ServiceException e) {
if (e.getCode() == 10009) { /* already exists: reuse it, don't fail the script */ }
} Prevention
- Make bootstrap scripts idempotent (check-then-create or catch 10009)
- Run tenant sync jobs on a single node or with a lock
- List existing tenants before bulk provisioning
- Don't blindly recreate tenants after failed setups
When it happens
Trigger: POST /tenants with a tenantCode that an earlier create already registered; createTenantIfNotExists races when two requests create the same tenant concurrently.
Common situations: Rerunning idempotency-broken bootstrap scripts; LDAP/SSO sync jobs running on multiple nodes simultaneously; admins recreating a tenant after a partially failed setup without checking existing tenants.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06).
Data as JSON: /api/errors/72b980e5e195cc0e.
Report an issue: GitHub.