HELGE SVERREAll-stack Developer
Bergen, Norwayv13.0
est. 2012  |  197 repos  |  12.8k+ contributions
Tools  |   Theme:
Fixing "The image manifest, config or layer media type is not supported" on Laravel Vapor
August 14, 2026

Deployed a Laravel app to Vapor and got this near the end:

Deployment Failed

AWS: The image manifest, config or layer media type for the source image
is not supported. InvalidParameterValueException

The build worked. Assets were uploaded. The image made it to ECR. Lambda just refused to use it.

Fix

For Vapor's normal x86 Docker runtime, add this to the environment in vapor.yml:

runtime: docker
docker-build-options:
  - platform=linux/amd64
  - provenance=false

Add it to every runtime: docker environment you build on that machine.

If the environment intentionally uses Vapor's ARM runtime, use ARM instead:

runtime: docker-arm
docker-build-options:
  - platform=linux/arm64
  - provenance=false

The docker-arm runtime also requires the ARM base image in your Dockerfile, such as FROM laravelphp/vapor:php84-arm. The base images reject a mismatched runtime.

You need both options. More on that below.

What was in ECR

I inspected the tag Vapor had pushed:

docker buildx imagetools inspect \
  123456789012.dkr.ecr.eu-north-1.amazonaws.com/my-app:deployment-tag

The interesting part looked like this:

MediaType: application/vnd.oci.image.index.v1+json

Manifests:
  Platform:  linux/arm64

  Platform:  unknown/unknown
  Annotation: vnd.docker.reference.type=attestation-manifest

So Vapor had not pushed one image manifest. It had pushed an OCI image index containing:

  1. An ARM64 image from my ARM64 development machine.
  2. A BuildKit provenance attestation.

The unknown/unknown entry looks broken, but that part is deliberate. BuildKit stores attestations as separate manifests and marks them with an unknown platform so runtimes do not try to execute them. Docker documents the layout in Attestation storage.

ECR is happy to store this. It supports Docker manifests, OCI manifests, and indexes. Lambda is pickier: its container image documentation says the image must target one architecture and that multi-architecture images are not supported.

This does not mean Lambda rejects OCI. It supports OCI image manifests. The problem here was the index containing multiple manifests, plus the wrong architecture for Vapor's x86 runtime.

That is why the two flags do separate jobs:

  • platform=linux/amd64 stops a build on Apple Silicon from targeting ARM64.
  • provenance=false stops BuildKit from adding the attestation manifest and wrapping the result in an index.

AWS uses the same combination in its own Lambda container examples, including the Python container image guide.

Why did it suddenly break?

The machine that produced the bad image was running Docker Engine 29.4 on ARM64 with a containerd-backed image store. The project had deployed fine before, so I checked whether Vapor had recently changed its image builder.

It had not.

Vapor CLI's Docker builder still runs a fairly plain docker build. The relevant code is unchanged between Vapor CLI v1.59 and v1.70.3. vapor-core does not build or push images at all.

The behavior came from Docker and BuildKit:

  • BuildKit v0.11 added provenance attestations, and Buildx v0.10 turned a minimal one on by default, both in January 2023. The Buildx release notes even warn that the resulting OCI output may break runtimes including Lambda, and recommend --provenance=false.
  • Docker Engine 23 made BuildKit and Buildx the default docker build path on Linux in February 2023.
  • Docker Engine 29 made the containerd image store the default for fresh installations in November 2025.

That last change matters because Docker's old image store cannot retain these multi-manifest attestation results. The containerd store can. The build can now pass the index all the way through the normal local build and push flow instead of dropping the extra metadata.

Docker 29 did not introduce provenance. It made a behavior that had existed since 2023 much easier to hit with an ordinary docker build followed by docker push. You can also hit it on older Docker versions if the containerd image store is enabled or Buildx pushes directly to the registry.

Vapor already had the escape hatch. PR #232, released in Vapor CLI v1.59 in August 2023, added docker-build-options, and Vapor's own environment docs already recommend provenance=false for ARM builds on CI. Vapor treats its architectures as separate runtimes, docker for x86 and docker-arm for ARM, and its x86 base Dockerfiles have been pinned to linux/amd64 since 2022. Setting both options just tells the local Docker installation which of those runtimes you are building for.

Check the result

After the image has been pushed, inspect it again:

docker buildx imagetools inspect <registry>/<repository>:<tag>

For runtime: docker, you want one runnable linux/amd64 image and no extra unknown/unknown attestation manifest. For runtime: docker-arm, you want one linux/arm64 image.

Setting only platform can still leave you with an index containing an attestation. Setting only provenance=false can still build for the wrong CPU. Set both.




<!-- generated with nested tables and zero regrets -->