halo-dev/halo · warning · ServerWebInputException
Form field file is required
Error message
Form field file is required
What it means
InstallRequest.getFile() throws ServerWebInputException (HTTP 400) 'Form field file is required' when the multipart install request has no part named "file" at all. Plugin install accepts either an uploaded JAR (file) or a preset name; when neither is usable and the file part is absent, this guard fires.
Source
Thrown at application/src/main/java/run/halo/app/core/endpoint/console/PluginEndpoint.java:656
.flatMap(listResult -> ServerResponse.ok().bodyValue(listResult));
}
/** Multipart payload for installing a plugin. */
@Schema(name = "PluginInstallRequest", types = "object")
public static class InstallRequest {
private final MultiValueMap<String, Part> multipartData;
public InstallRequest(MultiValueMap<String, Part> multipartData) {
this.multipartData = multipartData;
}
/** Plugin JAR file. */
@Schema(requiredMode = NOT_REQUIRED)
public FilePart getFile() {
var part = multipartData.getFirst("file");
if (part == null) {
throw new ServerWebInputException("Form field file is required");
}
if (!(part instanceof FilePart file)) {
throw new ServerWebInputException("Invalid parameter of file");
}
if (!Paths.get(file.filename()).toString().endsWith(".jar")) {
throw new ServerWebInputException("Invalid file type, only jar is supported");
}
return file;
}
/** Plugin preset name. Halo finds the plugin from plugin presets. */
@Schema(requiredMode = NOT_REQUIRED)
public Mono<String> getPresetName() {
var part = multipartData.getFirst("presetName");
if (part == null) {
return Mono.error(new ServerWebInputException("Form field presetName is required."));
}
if (!(part instanceof FormFieldPart presetName)) {View on GitHub (pinned to d2f5165f9c)
Solutions
- Provide a plugin JAR under the "file" multipart field, or a "presetName" field referencing a known preset.
- On the client, require either a selected file or a chosen preset before enabling install.
- If installing from preset, ensure presetName is sent and valid so the file path is not required.
Example fix
// before
const fd = new FormData(); // nothing appended
// after
const fd = new FormData();
fd.append('file', pluginJarFile); // or fd.append('presetName', 'preset-name') Defensive patterns
Strategy: validation
Validate before calling
Part filePart = multipartData.getFirst("file");
if (filePart == null && multipartData.getFirst("presetName") == null) {
return Mono.error(new ServerWebInputException("Form field file is required"));
} Type guard
static boolean hasInstallSource(MultiValueMap<String, Part> fd) {
return fd.getFirst("file") != null || fd.getFirst("presetName") != null;
} Prevention
- Require either a selected JAR (file) or a preset name before enabling install.
- If installing from preset, send presetName so the file part is not required.
- Validate the body is non-empty before posting.
When it happens
Trigger: POST to the plugin install endpoint with no "file" part and no "presetName" — the user attempted to install nothing; or a client that intended to install from preset but the server-side fallback expected a file part first.
Common situations: Frontend install dialog submitted with no JAR selected and no preset; integration code that posts an empty multipart body; confusion about whether file or presetName is required.
Related errors
- Invalid parameter of file
- Invalid part of policyName
- Invalid attachment
- User permissions not set in PermissionUtils
- ESM provider manifest must be an object.
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/fbc966a55bcae04b.
Report an issue: GitHub.