{"record":{"id":"3af6a944c1b6c4b5","repo":"apache/dolphinscheduler","slug":"delete-environment-error","errorCode":"DELETE_ENVIRONMENT_ERROR","errorMessage":"Status.DELETE_ENVIRONMENT_ERROR","messagePattern":"Status\\.DELETE_ENVIRONMENT_ERROR","errorType":"error_code","errorClass":"ServiceException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/EnvironmentServiceImpl.java","lineNumber":296,"sourceCode":"    @Transactional\n    @Override\n    public void deleteEnvironmentByCode(User loginUser, Long code) {\n        if (!canOperatorPermissions(loginUser, null, AuthorizationType.ENVIRONMENT, ENVIRONMENT_DELETE)) {\n            throw new ServiceException(Status.USER_NO_OPERATION_PERM);\n        }\n\n        long relatedTaskNumber = taskDefinitionDao.countByEnvironmentCode(code);\n\n        if (relatedTaskNumber > 0) {\n            log.warn(\"Delete environment failed because {} tasks is using it, environmentCode:{}.\",\n                    relatedTaskNumber, code);\n            throw new ServiceException(Status.DELETE_ENVIRONMENT_RELATED_TASK_EXISTS);\n        }\n\n        int delete = environmentMapper.deleteByCode(code);\n        if (delete <= 0) {\n            log.error(\"Environment delete error, environmentCode:{}.\", code);\n            throw new ServiceException(Status.DELETE_ENVIRONMENT_ERROR);\n        }\n        relationMapper.delete(new QueryWrapper<EnvironmentWorkerGroupRelation>()\n                .lambda()\n                .eq(EnvironmentWorkerGroupRelation::getEnvironmentCode, code));\n        log.info(\"Environment and relations delete complete, environmentCode:{}.\", code);\n    }\n\n    /**\n     * update environment\n     *\n     * @param loginUser login user\n     * @param code environment code\n     * @param name environment name\n     * @param config environment config\n     * @param desc environment desc\n     * @param workerGroups worker groups\n     */\n    @Transactional","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/EnvironmentServiceImpl.java#L278-L314","documentation":"Thrown by EnvironmentServiceImpl.deleteEnvironmentByCode when environmentMapper.deleteByCode returns <= 0 rows after the related-task check passed, meaning the DELETE affected no row. Usually indicates the environment was already deleted concurrently or a database-level failure prevented the delete.","triggerScenarios":"Race: another client deletes the same environment between the permission/task checks and the delete statement; DB write failure or constraint causing 0 affected rows; passing a code that vanished mid-transaction.","commonSituations":"Concurrent cleanup scripts running against the same environment list; UI double-click sending two delete requests where the second fails; DB replica/consistency issues.","solutions":["Verify the environment still exists (queryEnvironmentByCode); if not, treat the delete as already done and ignore this error.","Retry the delete once after confirming existence.","Check api-server logs and DB health if the row exists but deletes keep affecting 0 rows."],"exampleFix":"// before\nenvironmentService.deleteEnvironmentByCode(loginUser, code);\n// after\ntry {\n    environmentService.deleteEnvironmentByCode(loginUser, code);\n} catch (ServiceException e) {\n    if (environmentExists(code)) {\n        throw e; // real failure\n    } // else: already deleted concurrently — safe to ignore\n}","handlingStrategy":"try-catch","validationCode":"public void deleteIfPresent(User loginUser, long code) throws ServiceException {\n    try {\n        environmentService.queryEnvironmentByCode(code);\n    } catch (ServiceException gone) {\n        return; // already deleted\n    }\n    environmentService.deleteEnvironmentByCode(loginUser, code);\n}","typeGuard":null,"tryCatchPattern":"try {\n    environmentService.deleteEnvironmentByCode(loginUser, code);\n} catch (ServiceException e) {\n    if (String.valueOf(e.getMessage()).contains(\"DELETE_ENVIRONMENT_ERROR\")) {\n        boolean stillExists = true;\n        try { environmentService.queryEnvironmentByCode(code); } catch (ServiceException gone) { stillExists = false; }\n        if (!stillExists) return; // concurrent delete won; safe\n        // otherwise inspect DB, retry with backoff\n    }\n}","preventionTips":["Serialize environment deletions through a single process or lock to avoid races","Treat 'delete affected 0 rows' as success when a concurrent delete already removed the row","Retry once after confirming existence before escalating to DB diagnostics"],"tags":["dolphinscheduler","database","delete-failed","concurrency"],"backgroundTag":"database-write-failed","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}