{"record":{"id":"a71ea7e96f6a6902","repo":"halo-dev/halo","slug":"invalid-file-type-only-zip-format-is-supported","errorCode":null,"errorMessage":"Invalid file type, only zip format is supported","messagePattern":"Invalid file type, only zip format is supported","errorType":"http","errorClass":"ServerWebInputException","httpStatus":400,"severity":"error","filePath":"application/src/main/java/run/halo/app/theme/endpoint/ThemeEndpoint.java","lineNumber":531,"sourceCode":"    @Schema(name = \"ThemeInstallRequest\", types = \"object\")\n    public static class InstallRequest {\n\n        @Schema(hidden = true)\n        private final MultiValueMap<String, Part> multipartData;\n\n        public InstallRequest(MultiValueMap<String, Part> multipartData) {\n            this.multipartData = multipartData;\n        }\n\n        /** Theme zip file. */\n        @Schema(requiredMode = REQUIRED)\n        FilePart getFile() {\n            Part part = multipartData.getFirst(\"file\");\n            if (!(part instanceof FilePart file)) {\n                throw new ServerWebInputException(\"Invalid parameter of file, binary data is required\");\n            }\n            if (!Paths.get(file.filename()).toString().endsWith(\".zip\")) {\n                throw new ServerWebInputException(\"Invalid file type, only zip format is supported\");\n            }\n            return file;\n        }\n    }\n\n    /**\n     * Payload for installing a theme from a remote URI.\n     *\n     * @param uri remote URI of the theme ZIP file\n     */\n    public record InstallFromUriRequest(\n            @Schema(requiredMode = REQUIRED) URI uri) {}\n\n    Mono<ServerResponse> install(ServerRequest request) {\n        return request.multipartData()\n                .map(InstallRequest::new)\n                .map(InstallRequest::getFile)\n                .flatMap(filePart -> themeService.install(filePart.content()))","sourceCodeStart":513,"sourceCodeEnd":549,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/application/src/main/java/run/halo/app/theme/endpoint/ThemeEndpoint.java#L513-L549","documentation":"After confirming the 'file' part is a FilePart, InstallRequest.getFile() resolves the filename to a Path string and checks it ends with '.zip'. If not, a ServerWebInputException (HTTP 400) 'Invalid file type, only zip format is supported' is thrown. Only ZIP archives may be installed.","triggerScenarios":"Installing a theme packaged as a non-zip archive (.tar.gz, .rar, .7z) or a renamed file whose effective path does not end in .zip. Uses Paths.get(filename).toString().endsWith(\".zip\") so it normalizes path separators first.","commonSituations":"Downloading a theme distributed as tar.gz; build tooling emitting the wrong archive format; OS hiding/altering extensions.","solutions":["Repackage the theme as a .zip and re-upload.","Confirm the uploaded filename ends in '.zip' (note the check is on the filename, so double extensions like .zip.txt will fail).","If your theme source is a tarball, convert it to zip before install."],"exampleFix":"# before\n#   tar -czf theme.tar.gz theme/\n# after\n#   zip -r theme.zip theme/","handlingStrategy":"validation","validationCode":"// Client-side: enforce .zip before install\nconst name = Paths.get(file.name) /* conceptual */;\nif (!file.name.toLowerCase().endsWith(\".zip\")) {\n    showError(\"Only zip format is supported.\");\n    return;\n}","typeGuard":"function isZipArchive(name) {\n  return String(name).toLowerCase().endsWith(\".zip\");\n}","tryCatchPattern":"try { await installTheme(fd); }\ncatch (e) { if (/only zip format/.test(e.message)) alert(\"Use a .zip archive.\"); throw e; }","preventionTips":["Distribute and upload themes only as .zip archives.","Validate the filename extension client-side before upload.","Avoid double extensions that break the suffix check.","Verify with `unzip -t theme.zip` locally before uploading."],"tags":["theme","multipart","upload","validation"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}