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

  1. Provide a plugin JAR under the "file" multipart field, or a "presetName" field referencing a known preset.
  2. On the client, require either a selected file or a chosen preset before enabling install.
  3. 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

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


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/fbc966a55bcae04b. Report an issue: GitHub.