elunez/eladmin · error · BadRequestException
文件只能部署在opt目录或者home目录
Error message
文件只能部署在opt目录或者home目录
What it means
Second rule of AppServiceImpl.verification: App.deployPath (where the app will be deployed/run on target servers) must start with '/opt' or '/home', else BadRequestException('文件只能部署在opt目录或者home目录 '). Same whitelist rationale as the upload path check.
Source
Thrown at eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/AppServiceImpl.java:98
String appName = resources.getName();
if (appName.contains(";") || appName.contains("|") || appName.contains("&")) {
throw new IllegalArgumentException("非法的应用名称,请勿包含[; | &]等特殊字符");
}
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) {View on GitHub (pinned to 55fbf70595)
Solutions
- Set deployPath under /opt or /home (e.g. /opt/apps/my-service) and resubmit.
- Prepare the directory with correct ownership on every deploy target server.
- If a different root is organizationally required, modify verification() deliberately and re-audit the shell commands that consume deployPath in DeployServiceImpl.
Example fix
// before
app.setDeployPath("/usr/local/myapp"); // -> 400
// after
app.setDeployPath("/opt/apps/myapp"); Defensive patterns
Strategy: validation
Validate before calling
String deploy = form.getDeployPath();
if (!(deploy != null && (deploy.startsWith("/opt") || deploy.startsWith("/home")))) {
throw new IllegalArgumentException("deployPath must be under /opt or /home");
}
appService.create(form); // or update Type guard
boolean isWhitelistedPath(String p) {
return p != null && (p.startsWith("/opt") || p.startsWith("/home"));
} Try / catch
try {
appService.update(app);
} catch (BadRequestException e) {
if (e.getMessage().contains("只能部署在")) { showPathRuleError("deployPath"); return; }
throw e;
} Prevention
- Document the /opt//home rule in deployment runbooks so ops doesn't reach for /usr/local or /srv.
- Validate all three App paths at once in the form so users see every violation, not just the first.
- Remember startsWith semantics: '/optX' passes, 'opt/x' fails — always include the leading slash.
When it happens
Trigger: POST/PUT /api/app with deployPath such as '/usr/local/app', '/srv/deploy', '/root/app', or missing the leading slash ('home/app').
Common situations: Teams accustomed to /usr/local or /srv install roots; copying paths from older deployment docs; forgetting the leading '/'; multi-tenant servers where /opt is reserved.
Related errors
AI-assisted analysis of elunez/eladmin@55fbf70595 (2026-08-14).
Data as JSON: /api/errors/256f2837c2bcdfd0.
Report an issue: GitHub.