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:
- An ARM64 image from my ARM64 development machine.
- 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/amd64stops a build on Apple Silicon from targeting ARM64.provenance=falsestops 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 buildpath 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.
