Description

The bootBuildImage Gradle task fails because the pull() method in org.springframework.boot.buildpack.platform.docker.ImageApi.java uses hardcoded values (PLATFORM_API_VERSION or API_VERSION) to specify the Docker API version when building the request URI for image creation (pulling).

Since the fixed API versions are older than the minimum required by the latest Docker Engine versions, the API call fails with an HTTP 400 "Bad Request" error, preventing the image from being pulled and the build from completing.

Root Cause in ImageApi.java

In the pull() method, buildUrl() uses fixed API versions:

// ...
      URI createUri = (platform != null)
          ? buildUrl(PLATFORM_API_VERSION, "/images/create", "fromImage", reference, "platform", platform)
          : buildUrl("/images/create", "fromImage", reference);
// ...
        return inspect((platform != null) ? PLATFORM_API_VERSION : API_VERSION, reference);
// ...
  • When platform is not specified, the request is made with the fixed API_VERSION (which appears to be v1.24).
  • When platform is specified (e.g., in build.gradle), the request is made with the fixed PLATFORM_API_VERSION (which appears to be v1.41).

Neither of these fixed versions meets the minimum API version (1.44) required by modern Docker Engine installations.

Steps to Reproduce

  1. Project Setup: Create a standard Spring Boot project using the provided command: bash spring init \ --type=gradle-project-kotlin \ --language=java \ --bootVersion=3.5.7 \ --name=spring-bellsoft \ --groupId=internal.dev \ --artifactId=spring-bellsoft \ --packageName=internal.dev.spring_bellsoft \ --dependencies=web \ --javaVersion=17 \ spring-bellsoft
  2. Execute Task (Without imagePlatform): Run the bootBuildImage task. bash ./gradlew bootBuildImage
    • Expected Behavior: Image build succeeds using the Docker Engine's actual minimum supported API version (1.44 or higher).
    • Observed Behavior (Failure 1 - API v1.24): The build fails because the request uses an outdated API version (v1.24).
  3. Execute Task (With imagePlatform): Modify build.gradle.kts to specify a platform: kotlin import org.springframework.boot.gradle.tasks.bundling.BootBuildImage // Added line (snip) tasks.named<BootBuildImage>("bootBuildImage") { imagePlatform = "linux/amd64" } // Added line Then, run the task again: bash ./gradlew bootBuildImage
    • Observed Behavior (Failure 2 - API v1.41): The build fails because the request now uses a different outdated API version (v1.41).

Failure Details & Logs

Failure without imagePlatform (API v1.24)

The bootBuildImage output shows the request using /v1.24/:

> Task :bootBuildImage FAILED
...
* What went wrong:
Execution failed for task ':bootBuildImage'.
> Docker API call to '.../v1.24/images/create?fromImage=docker.io%2Fpaketobuildpacks%2Fbuilder-noble-java-tiny%3Alatest' failed with status code 400 "Bad Request" and message "client version 1.24 is too old. Minimum supported API version is 1.44, please upgrade your client to a newer version"

The dockerd log confirms the rejected request:

Nov 11 18:25:40 ... dockerd[43806]: time="2025-11-11T18:25:40.540416180+09:00" level=debug msg="error response for POST request" error-response="client version 1.24 is too old. Minimum supported API version is 1.44, please upgrade your client to a newer version" method=POST module=api request-url="/v1.24/images/create?fromImage=docker.io%2Fpaketobuildpacks%2Fbuilder-noble-java-tiny%3Alatest" status=400 vars="map[version:1.24]"

Failure with imagePlatform = "linux/amd64" (API v1.41)

The bootBuildImage output shows the request using /v1.41/:

> Docker API call to '.../v1.41/images/create?fromImage=docker.io%2Fpaketobuildpacks%2Fbuilder-noble-java-tiny%3Alatest&platform=linux%2Famd64' failed with status code 400 "Bad Request" and message "client version 1.41 is too old. Minimum supported API version is 1.44, please upgrade your client to a newer version"

The dockerd log confirms the rejected request:

Nov 11 18:24:27 ... dockerd[43806]: time="2025-11-11T18:24:27.597508445+09:00" level=debug msg="error response for POST request" error-response="client version 1.41 is too old. Minimum supported API version is 1.44, please upgrade your client to a newer version" method=POST module=api request-url="/v1.41/images/create?fromImage=docker.io%2Fpaketobuildpacks%2Fbuilder-noble-java-tiny%3Alatest&platform=linux%2Famd64" status=400 vars="map[version:1.41]"

Environment

Used Docker Engine Version

The installed Docker Engine requires a minimum API version of 1.44.

$ docker version
Client: Docker Engine - Community
 Version:           29.0.0
 API version:       1.52
...
Server: Docker Engine - Community
 Engine:
  Version:          29.0.0
  API version:      1.52 (minimum version 1.44)
...

curl Success Example (Using correct v1.52)

Manually using the correct API version works as expected:

$ curl -X POST --unix-socket /var/run/docker.sock \
  "http://localhost/v1.52/images/create?fromImage=docker.io%2Fpaketobuildpacks%2Fbuilder-noble-java-tiny%3Alatest"
{"status":"Pulling from paketobuildpacks/builder-noble-java-tiny","id":"latest"}
...
{"status":"Status: Image is up to date for paketobuildpacks/builder-noble-java-tiny:latest"}

Suggested Fix

The bootBuildImage utility should either:

  1. Dynamically determine the highest supported Docker API version using the /version endpoint and use it for requests, or
  2. Use the minimum supported API version (MinAPIVersion from /version endpoint, which is 1.44 in this case) to ensure compatibility with modern Docker Engine versions.

Comment From: wilkinsona

Thanks for the report. This is due to a breaking change in 29.0:

The daemon now requires API version v1.44 or later (Docker v25.0+).

We'll see what we can do. In the meantime, any earlier version of Docker should continue to work.

Comment From: fleboulch

I'm also impacted by this issue.
I'm using spring boot ̀3.5.7` and I cannot run my test suite (in local and in the CI) with testcontainers as usual.

Image

Comment From: wilkinsona

This issue is about Spring Boot's buildpacks support and is unrelated to Testcontainers. @fleboulch, I think https://github.com/testcontainers/testcontainers-java/issues/11212 is tracking the problem that you're facing.

Comment From: hiro345g

Thank you very much for the prompt response and clarification.

I understand that this issue is caused by the breaking change in Docker Engine 29.0, which mandates API version v1.44 or later.

We appreciate you looking into a fix for this. In the meantime, I wanted to share a specific, reproducible workaround that avoids manual Docker downgrades on the host machine and may be helpful for other users.


Temporary Local Workaround using Dev Containers (Dind)

For others facing this issue, I've confirmed a successful temporary workaround using a Docker-in-Docker (Dind) Dev Container configured with an older, compatible Docker version. This allows the bootBuildImage task to run successfully within the isolated container environment.

1. Dev Container Setup

Create a file named .devcontainer/devcontainer.json inside the root of the sample project (spring-bellsoft) with the following content:

{
  "name": "dvc-spring-bellsoft",
  "image": "[mcr.microsoft.com/devcontainers/base:ubuntu-24.04](https://mcr.microsoft.com/devcontainers/base:ubuntu-24.04)",
  "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
  "mounts": [
    {
      "source": "${localWorkspaceFolder}",
      "target": "/workspaces/${localWorkspaceFolderBasename}",
      "type": "bind"
    }
  ],  
  "features": {
    "ghcr.io/devcontainers/features/java:1": {
      "version": "17.0.17-librca",
      "jdkDistro": "liberica",
      "installGradle": true
    },
    "ghcr.io/devcontainers/features/docker-in-docker:2": {
      "version": "28.5.2",
      "moby": false
    }
  },
  "runArgs": ["--privileged"],
  "customizations": {
    "vscode": {
      "extensions": [
        "vscjava.vscode-java-pack",
        "ms-azuretools.vscode-docker"
      ]
    }
  },
  "forwardPorts": [8080],
  "postCreateCommand": "java -version && gradle --version && docker --version"
}
````

*The key is setting the `docker-in-docker` feature version to `28.5.2` to avoid the API version incompatibility.*

## 2\. Build and Export Image (Inside Dev Container)

After opening the project in the VS Code Dev Container, run the following commands in the container's terminal:

```bash
# Navigate to the project directory (if not already there)
cd /workspaces/spring-bellsoft

# Run bootBuildImage successfully using the isolated Docker 28.5.2 daemon
./gradlew bootBuildImage

# Export the built image from the Dev Container's Dind daemon to a .tar file.
# The .tar file is saved to the shared host volume mount.
docker image save spring-bellsoft:0.0.1-SNAPSHOT \
  -o /workspaces/spring-bellsoft/spring-bellsoft_0.0.1-SNAPSHOT.tar

This creates the spring-bellsoft_0.0.1-SNAPSHOT.tar file in the spring-bellsoft folder on your host machine.

3. Load Image to Host Docker (Outside Dev Container)

Finally, load the exported image into your main Docker Host environment. Run this command in your host machine's terminal:

# Navigate to the project directory on the host machine
cd ${PROJECT_DIR} 

# Load the image into the host's Docker daemon
docker image load -i spring-bellsoft_0.0.1-SNAPSHOT.tar

The spring-bellsoft:0.0.1-SNAPSHOT image is now available and ready to use on the Docker Host.

Comment From: TomBenjamins

Hello, we have a local gitlab installation that uses google cloud runners to run build jobs (docker+machine setup) with the google-debian-12 docker image The problem is we cannot control that base VM as it's controlled by Google, and that base VM has upgraded to Docker 29.0.

Most of our projects are based on spring boot 3.5.7 by now, but there are still some projects that cannot be upgraded and are based on spring boot 2.7.18. I assume the behavior is the same in this version of the spring boot maven plugin? Is there any possibility there will be a fix for this version as well?

greetings Tom Benjamins

Comment From: wilkinsona

I assume the behavior is the same in this version of the spring boot maven plugin?

I believe it will be, yes.

Is there any possibility there will be a fix for this version as well?

OSS support for Spring Boot 2.7.x ended in June 2023. If you have a support contract then please raise the problem through that channel and we can consider back-porting whatever fix is made here.

Comment From: allnightlong

@TomBenjamins

Hello, we have a local gitlab installation that uses google cloud runners to run build jobs (docker+machine setup) with the google-debian-12 docker image The problem is we cannot control that base VM as it's controlled by Google, and that base VM has upgraded to Docker 29.0.

I'm using gitlab as well (but cloud, not local installation), so I've managed to use this workaround: in .gitlab-ci.yaml instead of

services:
    - docker:dind

you should put

  services:
    - docker:28-dind

Comment From: philwebb

@hiro345g or anyone else watching this issue, once https://github.com/spring-projects/spring-boot/actions/runs/19321092466 has completed could you try the latest SNAPSHOT to see if the problem is resolved? Thanks!