spring-projects/spring-boot · error · ReportableException
Could not save the project, the server did not set a preferr
Error message
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.
What it means
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.
Source
Thrown at cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java:63
this.initializrService = initializrService;
}
void generateProject(ProjectGenerationRequest request, boolean force) throws IOException {
ProjectGenerationResponse response = this.initializrService.generate(request);
String fileName = (request.getOutput() != null) ? request.getOutput() : response.getFileName();
if (shouldExtract(request, response)) {
if (isZipArchive(response)) {
extractProject(response, request.getOutput(), force);
return;
}
else {
Log.info("Could not extract '" + response.getContentType() + "'");
// Use value from the server since we can't extract it
fileName = response.getFileName();
}
}
if (fileName == null) {
throw new ReportableException("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.");
}
writeProject(response, fileName, force);
}
/**
* Detect if the project should be extracted.
* @param request the generation request
* @param response the generation response
* @return if the project should be extracted
*/
private boolean shouldExtract(ProjectGenerationRequest request, ProjectGenerationResponse response) {
if (request.isExtract()) {
return true;
}
// explicit name hasn't been provided for an archive and there is no extension
return isZipArchive(response) && request.getOutput() != null && !request.getOutput().contains(".");
}View on GitHub (pinned to 5b2dbdbb8b)
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.
Example fix
// before $ spring init myapp # server returned no filename // after $ spring init --output myapp.zip myapp
Defensive patterns
Strategy: validation
Validate before calling
String out = request.getOutput();
boolean serverNamesFile = (response != null && response.getFileName() != null);
if (out == null && !serverNamesFile) {
throw new IllegalStateException("No output location and server provided no filename; set --output.");
} Type guard
boolean canPersist = request.getOutput() != null
|| (response != null && response.getFileName() != null); Try / catch
// Not recommended: the CLI is the caller here. Instead validate pre-call.
// If embedding ProjectGenerator:
try { generator.generateProject(request, force); }
catch (ReportableException ex) {
if (ex.getMessage().startsWith("Could not save the project")) {
request.setOutput("project.zip");
generator.generateProject(request, force);
} else throw ex;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- {Directory|File} '{file.getName()}' already exists. Use --fo
- File '{outputFile.getName()}' already exists. Use --force if
- No project type with id '${this.type}' - check the service c
- No type found with build '{this.build}' and format '{this.fo
- Multiple types found with build '{this.build}' and format '{
AI-assisted analysis of spring-projects/spring-boot@5b2dbdbb8b (2026-08-04).
Data as JSON: /data/errors/abb02e3dca28e29c.json.
Report an issue: GitHub.