{"id":"abb02e3dca28e29c","repo":"spring-projects/spring-boot","slug":"could-not-save-the-project-the-server-did-not-set","errorCode":null,"errorMessage":"Could not save the project, the server did not set a preferred file name and no location was set. Specify the output location for the project.","messagePattern":"Could not save the project, the server did not set a preferred file name and no location was set\\. Specify the output location for the project\\.","errorType":"exception","errorClass":"ReportableException","httpStatus":null,"severity":"error","filePath":"cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java","lineNumber":63,"sourceCode":"\t\tthis.initializrService = initializrService;\n\t}\n\n\tvoid generateProject(ProjectGenerationRequest request, boolean force) throws IOException {\n\t\tProjectGenerationResponse response = this.initializrService.generate(request);\n\t\tString fileName = (request.getOutput() != null) ? request.getOutput() : response.getFileName();\n\t\tif (shouldExtract(request, response)) {\n\t\t\tif (isZipArchive(response)) {\n\t\t\t\textractProject(response, request.getOutput(), force);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tLog.info(\"Could not extract '\" + response.getContentType() + \"'\");\n\t\t\t\t// Use value from the server since we can't extract it\n\t\t\t\tfileName = response.getFileName();\n\t\t\t}\n\t\t}\n\t\tif (fileName == null) {\n\t\t\tthrow new ReportableException(\"Could not save the project, the server did not set a preferred \"\n\t\t\t\t\t+ \"file name and no location was set. Specify the output location for the project.\");\n\t\t}\n\t\twriteProject(response, fileName, force);\n\t}\n\n\t/**\n\t * Detect if the project should be extracted.\n\t * @param request the generation request\n\t * @param response the generation response\n\t * @return if the project should be extracted\n\t */\n\tprivate boolean shouldExtract(ProjectGenerationRequest request, ProjectGenerationResponse response) {\n\t\tif (request.isExtract()) {\n\t\t\treturn true;\n\t\t}\n\t\t// explicit name hasn't been provided for an archive and there is no extension\n\t\treturn isZipArchive(response) && request.getOutput() != null && !request.getOutput().contains(\".\");\n\t}","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/spring-projects/spring-boot/blob/5b2dbdbb8be64415eb6552f81ff7c449c8d251e6/cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java#L45-L81","documentation":"Thrown by ProjectGenerator.generateProject when the project was generated as a non-extractable response (or extraction was skipped) and the resolved file name is null - i.e. neither the user supplied --output nor the server returned a preferred file name via Content-Disposition. With no target path the bytes cannot be written anywhere.","triggerScenarios":"Calling `spring init` without --output, when the Initializr response carries no 'fileName' (ProjectGenerationResponse.getFileName() returns null) and the response is not a zip being extracted. Line 50 falls through and line 62 sees fileName == null.","commonSituations":"Custom Initializr that omits the Content-Disposition header; response content type isn't application/zip so extraction isn't attempted; a proxy stripping headers; an older/newer service version that changed its header behavior.","solutions":["Pass an explicit output location: `spring init --output myapp.zip` (or `myapp/` to extract).","If you control the service, ensure it sets Content-Disposition with a filename for non-zip or non-extracted responses.","If extraction is intended, ensure the response Content-Type is application/zip so shouldExtract() returns true and extraction writes under the output directory."],"exampleFix":"// before\n$ spring init myapp   # server returned no filename\n// after\n$ spring init --output myapp.zip myapp","handlingStrategy":"validation","validationCode":"String out = request.getOutput();\nboolean serverNamesFile = (response != null && response.getFileName() != null);\nif (out == null && !serverNamesFile) {\n    throw new IllegalStateException(\"No output location and server provided no filename; set --output.\");\n}","typeGuard":"boolean canPersist = request.getOutput() != null\n    || (response != null && response.getFileName() != null);","tryCatchPattern":"// Not recommended: the CLI is the caller here. Instead validate pre-call.\n// If embedding ProjectGenerator:\ntry { generator.generateProject(request, force); }\ncatch (ReportableException ex) {\n    if (ex.getMessage().startsWith(\"Could not save the project\")) {\n        request.setOutput(\"project.zip\");\n        generator.generateProject(request, force);\n    } else throw ex;\n}","preventionTips":["Always pass --output in scripts so generation is independent of server headers.","If you operate the Initializr, ensure Content-Disposition filenames are set for all content types.","Confirm proxies don't strip Content-Disposition before it reaches the CLI."],"tags":["spring-boot-cli","initializr","project-generation","file-io"],"analyzedSha":"5b2dbdbb8be64415eb6552f81ff7c449c8d251e6","analyzedAt":"2026-08-04T18:53:14.967Z","schemaVersion":2}