alibaba/spring-ai-alibaba · error · RuntimeException

Failed to stop experiment

Error message

Failed to stop experiment

What it means

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.

Source

Thrown at spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/service/impl/ExperimentServiceImpl.java:291


        // 检查实验状态
        if (ExperimentStatus.COMPLETED.getCode().equals(experimentDO.getStatus()) ||
            ExperimentStatus.FAILED.getCode().equals(experimentDO.getStatus()) ||
            ExperimentStatus.STOPPED.getCode().equals(experimentDO.getStatus())) {
            log.warn("实验 {} 状态为 {},无法停止", id, experimentDO.getStatus());
            return Experiment.fromDO(experimentDO);
        }


        
        // 更新实验状态为已停止
        experimentDO.setStatus(String.valueOf(ExperimentStatus.STOPPED));
        experimentDO.setUpdateTime(LocalDateTime.now());
        
        int result = experimentMapper.updateById(experimentDO);
        if (result <= 0) {
            throw new RuntimeException("Failed to stop experiment");
        }
        
        log.info("实验停止成功: {}", id);
        return Experiment.fromDO(experimentDO);
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        log.info("删除实验: {}", id);
        
        if (id == null) {
            throw new IllegalArgumentException("Experiment ID cannot be null");
        }
        
        // 检查实验是否存在
        ExperimentDO experimentDO = experimentMapper.selectById(id);
        if (experimentDO == null) {

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Verify the experiment id exists (experimentMapper.selectById) before calling stop
  2. Re-check whether the experiment was already stopped or deleted and make the stop operation idempotent
  3. Check database connectivity/permissions and logs for the underlying SQL failure
  4. Catch RuntimeException in the controller and return a 404/409 with a clear message

Example fix

// before
experimentDO.setStatus(String.valueOf(ExperimentStatus.STOPPED));
int result = experimentMapper.updateById(experimentDO);
if (result <= 0) {
    throw new RuntimeException("Failed to stop experiment");
}
// after
ExperimentDO existing = experimentMapper.selectById(id);
if (existing == null) {
    throw new IllegalArgumentException("Experiment not found: " + id);
}
existing.setStatus(String.valueOf(ExperimentStatus.STOPPED));
existing.setUpdateTime(LocalDateTime.now());
int result = experimentMapper.updateById(existing);
if (result <= 0) {
    throw new IllegalStateException("Failed to stop experiment: " + id);
}
Defensive patterns

Strategy: try-catch

Validate before calling

ExperimentDO exp = experimentMapper.selectById(id);
if (exp == null) throw new IllegalArgumentException("not found: " + id);
if (ExperimentStatus.STOPPED.getCode().equals(exp.getStatus())) return; // already stopped

Type guard

boolean existsAndStoppable(Long id) { ExperimentDO e = experimentMapper.selectById(id); return e != null && !ExperimentStatus.STOPPED.getCode().equals(e.getStatus()); }

Try / catch

try { experimentService.stop(id); } catch (RuntimeException e) { log.warn("stop failed for {}", id, e); /* check existence, rethrow 404/409 */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/26fa9ced399c795b. Report an issue: GitHub.