An image built on an Apple Silicon laptop is arm64 and the servers are amd64, and the failure is an exec format error with nothing else to go on.
$ docker run registry/app:latest
exec /usr/local/bin/docker-entrypoint.sh: exec format error
$ docker image inspect registry/app:latest --format '{{.Architecture}}'
arm64
# for an image only your servers pull
$ docker buildx build --platform linux/amd64 -t app --push .
# for one other people pull: a manifest list
$ docker buildx build --platform linux/amd64,linux/arm64 ...
Emulated builds are slow enough — often five times — that a native runner per architecture is worth the pipeline complexity once the build takes minutes. The check belongs in the deploy script rather than in somebody’s memory: inspecting the architecture of the pulled image before releasing it turns a confusing runtime failure into a clear refusal.