{"record":{"id":"642331c02ff7bd3c","repo":"apache/dolphinscheduler","slug":"can-not-create-or-update-workflow-for-user-who-not","errorCode":null,"errorMessage":"Can not create or update workflow for user who not related to any tenant.","messagePattern":"Can not create or update workflow for user who not related to any tenant\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/python/PythonGateway.java","lineNumber":247,"sourceCode":"    public Long createOrUpdateWorkflow(String userName,\n                                       String projectName,\n                                       String name,\n                                       String description,\n                                       String globalParams,\n                                       String schedule,\n                                       boolean onlineSchedule,\n                                       String warningType,\n                                       int warningGroupId,\n                                       int timeout,\n                                       String workerGroup,\n                                       int releaseState,\n                                       String taskRelationJson,\n                                       String taskDefinitionJson,\n                                       String otherParamsJson,\n                                       String executionType) {\n        User user = usersService.queryUser(userName);\n        if (user.getTenantCode() == null) {\n            throw new RuntimeException(\"Can not create or update workflow for user who not related to any tenant.\");\n        }\n\n        Project project = projectDao.queryByName(projectName);\n        long projectCode = project.getCode();\n\n        WorkflowDefinition workflowDefinition = getWorkflow(user, projectCode, name);\n        WorkflowExecutionTypeEnum executionTypeEnum = WorkflowExecutionTypeEnum.valueOf(executionType);\n        long workflowDefinitionCode;\n        // create or update workflow\n        if (workflowDefinition != null) {\n            workflowDefinitionCode = workflowDefinition.getCode();\n            // make sure workflow offline which could edit\n            workflowDefinitionService.offlineWorkflowDefinition(user, projectCode, workflowDefinitionCode);\n            workflowDefinitionService.updateWorkflowDefinition(user, projectCode, name,\n                    workflowDefinitionCode, description, globalParams,\n                    null, timeout, taskRelationJson, taskDefinitionJson,\n                    executionTypeEnum);\n        } else {","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/python/PythonGateway.java#L229-L265","documentation":"PythonGateway.createOrUpdateWorkflow (the PyDolphinScheduler gateway) looks up the caller by userName; if the account exists but has no tenant bound (user.getTenantCode() == null) it refuses to create or update the workflow with a RuntimeException, because submitted workflows need a tenant under which tasks run.","triggerScenarios":"pydolphinscheduler submits a workflow (create or update) using a user account created without a tenant assignment.","commonSituations":"Admin created the API user but forgot to assign a tenant; tenant was later unbound; scripted user provisioning skipped tenantCode.","solutions":["Assign a tenant to the user (UI: Security -> User Management -> edit user -> choose Tenant) or via the user-update API with a tenantCode","Retry the pydolphinscheduler submission after binding the tenant","If the user is missing entirely, create it with createUserIfNotExists including tenantCode"],"exampleFix":"// before\nUser user = usersService.queryUser(userName);\nif (user.getTenantCode() == null) { ... }\n// after: check user presence AND tenant on caller side\nUser user = usersService.queryUser(userName);\nif (user == null) { throw new RuntimeException(\"User not found: \" + userName); }\nif (user.getTenantCode() == null) {\n    usersService.grantTenantToUser(user.getId(), defaultTenantId);\n}","handlingStrategy":"validation","validationCode":"# python client side, before submitting\nuser = gateway_client.query_user_by_name(user_name)\nif user is None:\n    user = create_user_if_not_exists(user_name, tenant_code=\"default\")\nelif user.get(\"tenant_code\") is None:\n    raise ValueError(f\"user {user_name} has no tenant; assign one before submitting workflows\")","typeGuard":"// java side\nboolean hasTenant(User user) {\n    return user != null && user.getTenantCode() != null && !user.getTenantCode().isEmpty();\n}","tryCatchPattern":"try {\n    pythonGateway.createOrUpdateWorkflow(...);\n} catch (RuntimeException e) {\n    if (e.getMessage().contains(\"not related to any tenant\")) {\n        log.warn(\"bind tenant to user {} and resubmit\", userName);\n    }\n    throw e;\n}","preventionTips":["Always assign a tenant when provisioning gateway/API users","Add tenantCode to user-creation automation scripts","Validate tenant binding in CI before workflow submission","Reject user creation without tenant in custom provisioning flows"],"tags":["python-gateway","tenant","workflow"],"backgroundTag":"missing-required-config-field","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}