{"record":{"id":"4d60af27fb4e271e","repo":"halo-dev/halo","slug":"invalid-part-of-file-4d60af","errorCode":null,"errorMessage":"Invalid part of file","messagePattern":"Invalid part of file","errorType":"validation","errorClass":"ServerWebInputException","httpStatus":400,"severity":"error","filePath":"application/src/main/java/run/halo/app/core/endpoint/console/UserEndpoint.java","lineNumber":405,"sourceCode":"    }\n\n    /** Multipart payload for uploading a user avatar. */\n    @Schema(types = \"object\")\n    public interface IAvatarUploadRequest {\n        /** Avatar file. */\n        @Schema(requiredMode = REQUIRED)\n        FilePart getFile();\n    }\n\n    public record AvatarUploadRequest(MultiValueMap<String, Part> formData) {\n        public FilePart getFile() {\n            Part file = formData.getFirst(\"file\");\n            if (file == null) {\n                throw new ServerWebInputException(\"No file part found in the request\");\n            }\n\n            if (!(file instanceof FilePart filePart)) {\n                throw new ServerWebInputException(\"Invalid part of file\");\n            }\n\n            boolean isNoneExt = Arrays.stream(ALLOWED_AVATAR_EXTENSIONS)\n                    .noneMatch(ext -> filePart.filename().endsWith(\".\" + ext));\n\n            if (isNoneExt) {\n                throw new ServerWebInputException(\n                        \"Only support file with extension: \" + String.join(\", \", ALLOWED_AVATAR_EXTENSIONS));\n            }\n            return filePart;\n        }\n    }\n\n    private Mono<Attachment> uploadAvatar(AvatarUploadRequest uploadRequest) {\n        var fallbackSetting = environmentFetcher\n                .fetch(SystemSetting.User.GROUP, SystemSetting.User.class)\n                .mapNotNull(SystemSetting.User::getAvatarPolicy)\n                .filter(StringUtils::isNotBlank);","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/application/src/main/java/run/halo/app/core/endpoint/console/UserEndpoint.java#L387-L423","documentation":"Thrown as a ServerWebInputException (HTTP 400) by AvatarUploadRequest.getFile() when a part named 'file' exists but is NOT an instance of FilePart — typically it is a FormFieldPart (a plain text field) rather than an uploaded file.","triggerScenarios":"POST to the avatar upload endpoint where the 'file' field is submitted as a normal text form field (e.g. -F 'file=some-string') instead of as a file attachment (-F 'file=@path').","commonSituations":"Client serialized the file path string into the field instead of attaching the binary; misconfigured form library sent the field as text; API client set 'file' as a string parameter rather than a file upload parameter.","solutions":["Attach the avatar as a file upload under the 'file' field (use type 'file' / '@file' semantics in your HTTP client), not a string.","Confirm the multipart part has a filename and Content-Type header, which is what makes WebFlux parse it as a FilePart."],"exampleFix":"// before: client sends file as text  ->  file='/path/me.png'\n// after:  client sends file as upload ->  file=@/path/me.png (type=file)","handlingStrategy":"validation","validationCode":"// ensure the part is a real file upload, not a text value\nif (!(selectedFile instanceof Blob) && !(selectedFile instanceof File)) {\n    showUserError(\"Attach an actual file, not text\");\n    return;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Configure the HTTP client field as a file upload (type 'file'), not a string.","Ensure the part carries a filename so WebFlux parses it as a FilePart."],"tags":["user","avatar","upload","multipart","validation"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}