# Docker Compose "services.X.build must be a string or object" in Builds

> Fix Docker Compose "services.X.build must be a string or object" in CI - a malformed build key, usually a list or a misindented mapping under a service.

Source: https://latchkey.dev/learn/docker/docker-build-services-build-must-be-string-or-object  
Updated: 2026-06-25

Compose validated the `build` key of a service and found the wrong YAML type. `build` must be either a string (a context path) or a mapping (`context`, `dockerfile`, …) - not a list or scalar of another type.

## Diagnose it: build context, cache, or platform?

A Dockerfile that builds locally and fails in CI usually differs in one of three ways: the build context contains different files, the layer cache is cold or poisoned, or the runner architecture does not match what the base image provides.

```Terminal
# what is actually being sent as build context (dockerignore applies)
docker build --no-cache --progress=plain -t probe . 2>&1 | head -40

# what platform are you on, and what does the base image support?
docker version --format '{{.Server.Arch}}'
docker buildx imagetools inspect <base-image> | grep -i platform

# prove it is not a cache artefact
docker build --no-cache .
```

> `--progress=plain` prints full step output instead of the collapsed TTY view. On a runner the collapsed view hides the line that actually failed, which is why the CI log often looks less informative than your local run.

## Keep the build context small and deterministic

- A missing `.dockerignore` sends `node_modules`, `.git`, and build output to the daemon, which is slow and can change layer hashes between environments.
- A `COPY` of a path that exists locally but is gitignored will fail in CI, because the runner only has what the checkout produced.
- Multi-arch builds need `buildx` and QEMU set up explicitly; a plain `docker build` on an ARM runner silently produces an ARM image.

## FAQ

### What causes Docker Compose "services.X.build must be a string or object" in builds?

There are 3 common causes: build written as a list, wrong indentation under the service, and a scalar of the wrong shape. A stray - turns the build mapping into a list (build:\n - context: ...).

### How do I fix Docker Compose "services.X.build must be a string or object" in builds?

There are 2 fixes depending on which cause you have: use a valid string or mapping form and validate the compose config. Work through them in order, since the first is the most common.

### What does Docker Compose "services.X.build must be a string or object" in builds actually mean?

A docker compose build or up --build fails during config validation with services.<name>.build must be a string or object, before any image is built.

### How do I stop Docker Compose "services.X.build must be a string or object" in builds happening again?

Run docker compose config in CI to validate before building. The prevention section lists 3 changes that keep it from recurring.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
