halo-dev/halo · error · ServerWebInputException

Only support file with extension: {}

Error message

Only support file with extension: {}

What it means

Thrown as a ServerWebInputException (HTTP 400) by AvatarUploadRequest.getFile() when the uploaded file's extension is not in ALLOWED_AVATAR_EXTENSIONS. The message interpolates the allowed list (e.g. png, jpg, jpeg, gif, webp) so the caller knows what is accepted.

Source

Thrown at application/src/main/java/run/halo/app/core/endpoint/console/UserEndpoint.java:412

        FilePart getFile();
    }

    public record AvatarUploadRequest(MultiValueMap<String, Part> formData) {
        public FilePart getFile() {
            Part file = formData.getFirst("file");
            if (file == null) {
                throw new ServerWebInputException("No file part found in the request");
            }

            if (!(file instanceof FilePart filePart)) {
                throw new ServerWebInputException("Invalid part of file");
            }

            boolean isNoneExt = Arrays.stream(ALLOWED_AVATAR_EXTENSIONS)
                    .noneMatch(ext -> filePart.filename().endsWith("." + ext));

            if (isNoneExt) {
                throw new ServerWebInputException(
                        "Only support file with extension: " + String.join(", ", ALLOWED_AVATAR_EXTENSIONS));
            }
            return filePart;
        }
    }

    private Mono<Attachment> uploadAvatar(AvatarUploadRequest uploadRequest) {
        var fallbackSetting = environmentFetcher
                .fetch(SystemSetting.User.GROUP, SystemSetting.User.class)
                .mapNotNull(SystemSetting.User::getAvatarPolicy)
                .filter(StringUtils::isNotBlank);
        var getAvatarPolicy = environmentFetcher
                .fetch(SystemSetting.Attachment.GROUP, SystemSetting.Attachment.class)
                .mapNotNull(SystemSetting.Attachment::avatar)
                .mapNotNull(UploadOptions::policyName)
                .filter(StringUtils::isNotBlank)
                .switchIfEmpty(fallbackSetting)
                .defaultIfEmpty(DEFAULT_USER_AVATAR_ATTACHMENT_POLICY_NAME);

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Convert the image to one of the allowed formats (png/jpg/jpeg/gif/webp) before uploading.
  2. Rename the file to use an allowed extension only if the actual content matches that format.
  3. If a new format is genuinely required, extend ALLOWED_AVATAR_EXTENSIONS and ensure the storage/attachment policy supports it.

Example fix

// before: upload avatar.bmp
// after:  convert to png, upload avatar.png
Defensive patterns

Strategy: validation

Validate before calling

// check extension against the allow-list before upload
Set<String> allowed = Set.of("png", "jpg", "jpeg", "gif", "webp");
String ext = name.substring(name.lastIndexOf('.') + 1).toLowerCase(Locale.ROOT);
if (!allowed.contains(ext)) {
    showUserError("Allowed: " + allowed);
    return;
}

Prevention

When it happens

Trigger: POST to the avatar upload endpoint with a file whose extension is not in the allow-list — e.g. .bmp, .svg, .tif, .heic, or a file with no extension. The check is a simple endsWith so a missing dot also fails.

Common situations: User picks a HEIC photo from a phone; SVG intended as a logo; screenshot saved as .bmp; filename lost its extension during transfer; admin wants a format not in the default allow-list.

Related errors


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