elunez/eladmin · error · BadRequestException

文件只能备份在opt目录或者home目录

Error message

文件只能备份在opt目录或者home目录 

What it means

Third rule of AppServiceImpl.verification: App.backupPath (where pre-deploy backups are stored) must start with '/opt' or '/home', else BadRequestException('文件只能备份在opt目录或者home目录 '). Backups are written by the deployment job, so their location is whitelisted the same way.

Source

Thrown at eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/AppServiceImpl.java:101

        }
        verification(resources);
        App app = appRepository.findById(resources.getId()).orElseGet(App::new);
        ValidationUtil.isNull(app.getId(),"App","id",resources.getId());
        app.copy(resources);
        appRepository.save(app);
    }

    private void verification(App resources){
        String opt = "/opt";
        String home = "/home";
        if (!(resources.getUploadPath().startsWith(opt) || resources.getUploadPath().startsWith(home))) {
            throw new BadRequestException("文件只能上传在opt目录或者home目录 ");
        }
        if (!(resources.getDeployPath().startsWith(opt) || resources.getDeployPath().startsWith(home))) {
            throw new BadRequestException("文件只能部署在opt目录或者home目录 ");
        }
        if (!(resources.getBackupPath().startsWith(opt) || resources.getBackupPath().startsWith(home))) {
            throw new BadRequestException("文件只能备份在opt目录或者home目录 ");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Long> ids) {
        for (Long id : ids) {
            appRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<AppDto> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (AppDto appDto : queryAll) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("应用名称", appDto.getName());
            map.put("端口", appDto.getPort());

View on GitHub (pinned to 55fbf70595)

Solutions

  1. Point backupPath to /opt/... or /home/... (e.g. /opt/eladmin/backup) and resubmit.
  2. Ensure the directory exists and is writable by the deploying service account on target machines.
  3. Keep all three App paths consistently under one whitelisted root to avoid partial validation failures.

Example fix

// before
app.setBackupPath("/data/backup/myapp"); // -> 400

// after
app.setBackupPath("/opt/eladmin/backup/myapp");
Defensive patterns

Strategy: validation

Validate before calling

String backup = form.getBackupPath();
if (!(backup != null && (backup.startsWith("/opt") || backup.startsWith("/home")))) {
    throw new IllegalArgumentException("backupPath must be under /opt or /home");
}
appService.create(form);

Type guard

boolean isWhitelistedPath(String p) {
    return p != null && (p.startsWith("/opt") || p.startsWith("/home"));
}

Try / catch

try {
    appService.create(app);
} catch (BadRequestException e) {
    if (e.getMessage().contains("只能备份在")) { showPathRuleError("backupPath"); return; }
    throw e;
}

Prevention

When it happens

Trigger: POST/PUT /api/app with backupPath like '/tmp/backup', '/data/backup', or 'backup/' (relative). All three paths — upload, deploy, backup — are validated in one pass, so the first failing one names the message.

Common situations: Ops conventions using /data or /var/backups; cloned App rows with edited backup paths; forgetting that backupPath is mandatory and validated even if you never intend to roll back.

Related errors


AI-assisted analysis of elunez/eladmin@55fbf70595 (2026-08-14). Data as JSON: /api/errors/0af5138bc3dd40c1. Report an issue: GitHub.