{"record":{"id":"26fa9ced399c795b","repo":"alibaba/spring-ai-alibaba","slug":"failed-to-stop-experiment","errorCode":null,"errorMessage":"Failed to stop experiment","messagePattern":"Failed to stop experiment","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/service/impl/ExperimentServiceImpl.java","lineNumber":291,"sourceCode":"\n\n        // 检查实验状态\n        if (ExperimentStatus.COMPLETED.getCode().equals(experimentDO.getStatus()) ||\n            ExperimentStatus.FAILED.getCode().equals(experimentDO.getStatus()) ||\n            ExperimentStatus.STOPPED.getCode().equals(experimentDO.getStatus())) {\n            log.warn(\"实验 {} 状态为 {}，无法停止\", id, experimentDO.getStatus());\n            return Experiment.fromDO(experimentDO);\n        }\n\n\n        \n        // 更新实验状态为已停止\n        experimentDO.setStatus(String.valueOf(ExperimentStatus.STOPPED));\n        experimentDO.setUpdateTime(LocalDateTime.now());\n        \n        int result = experimentMapper.updateById(experimentDO);\n        if (result <= 0) {\n            throw new RuntimeException(\"Failed to stop experiment\");\n        }\n        \n        log.info(\"实验停止成功: {}\", id);\n        return Experiment.fromDO(experimentDO);\n    }\n\n    @Override\n    @Transactional\n    public void deleteById(Long id) {\n        log.info(\"删除实验: {}\", id);\n        \n        if (id == null) {\n            throw new IllegalArgumentException(\"Experiment ID cannot be null\");\n        }\n        \n        // 检查实验是否存在\n        ExperimentDO experimentDO = experimentMapper.selectById(id);\n        if (experimentDO == null) {","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/service/impl/ExperimentServiceImpl.java#L273-L309","documentation":"Thrown by ExperimentServiceImpl.stop when the MyBatis-Plus updateById call returns 0 rows affected, meaning the experiment row could not be updated to STOPPED status. The library treats any non-positive update result as a hard failure and wraps it in a RuntimeException.","triggerScenarios":"Calling stop(id) for an experiment whose row no longer exists (deleted concurrently), an id pointing to a non-existent record, or a database write failure/constraint that prevents the update.","commonSituations":"Race condition where the experiment is deleted by another request/thread while stop is in flight; wrong id passed from the client; database connectivity or permission issues in the admin server environment.","solutions":["Verify the experiment id exists (experimentMapper.selectById) before calling stop","Re-check whether the experiment was already stopped or deleted and make the stop operation idempotent","Check database connectivity/permissions and logs for the underlying SQL failure","Catch RuntimeException in the controller and return a 404/409 with a clear message"],"exampleFix":"// before\nexperimentDO.setStatus(String.valueOf(ExperimentStatus.STOPPED));\nint result = experimentMapper.updateById(experimentDO);\nif (result <= 0) {\n    throw new RuntimeException(\"Failed to stop experiment\");\n}\n// after\nExperimentDO existing = experimentMapper.selectById(id);\nif (existing == null) {\n    throw new IllegalArgumentException(\"Experiment not found: \" + id);\n}\nexisting.setStatus(String.valueOf(ExperimentStatus.STOPPED));\nexisting.setUpdateTime(LocalDateTime.now());\nint result = experimentMapper.updateById(existing);\nif (result <= 0) {\n    throw new IllegalStateException(\"Failed to stop experiment: \" + id);\n}","handlingStrategy":"try-catch","validationCode":"ExperimentDO exp = experimentMapper.selectById(id);\nif (exp == null) throw new IllegalArgumentException(\"not found: \" + id);\nif (ExperimentStatus.STOPPED.getCode().equals(exp.getStatus())) return; // already stopped","typeGuard":"boolean existsAndStoppable(Long id) { ExperimentDO e = experimentMapper.selectById(id); return e != null && !ExperimentStatus.STOPPED.getCode().equals(e.getStatus()); }","tryCatchPattern":"try { experimentService.stop(id); } catch (RuntimeException e) { log.warn(\"stop failed for {}\", id, e); /* check existence, rethrow 404/409 */ }","preventionTips":["Check the experiment exists before stopping","Make stop idempotent for already-stopped experiments","Monitor DB connectivity in the admin server"],"tags":["database","mybatis","experiment-lifecycle"],"backgroundTag":"database-write-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}