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
- Point backupPath to /opt/... or /home/... (e.g. /opt/eladmin/backup) and resubmit.
- Ensure the directory exists and is writable by the deploying service account on target machines.
- 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
- Plan backup space under the whitelisted root and provision it with ample capacity.
- Keep upload/deploy/backup paths consistent under one root to pass validation in one shot.
- Do not point backups at /tmp or /data — they will be rejected and are also unsafe locations.
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.