# Compose "service ... refers to undefined secret" in CI

> Fix Compose "service X refers to undefined secret Y" in CI - a service lists a secret that has no matching top-level secrets entry.

Source: https://latchkey.dev/learn/docker/docker-compose-secrets-top-level-not-found-in-ci  
Updated: 2026-06-30

A service secret must reference a secret declared in the top-level `secrets:` block. If the name under the service has no matching top-level definition, Compose reports it as undefined and refuses to start.

## 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 Compose "service ... refers to undefined secret" in CI?

There are 2 common causes: no matching top-level secrets entry and a name mismatch between service and top level. The service lists a secret name that is never declared under the top-level secrets: key.

### How do I fix Compose "service ... refers to undefined secret" in CI?

There are 2 fixes depending on which cause you have: declare the secret at the top level and provide the secret source in ci. Work through them in order, since the first is the most common.

### What does Compose "service ... refers to undefined secret" in CI actually mean?

A compose command fails with "service \"app\" refers to undefined secret \"db_password\": invalid compose project".

### How do I stop Compose "service ... refers to undefined secret" in CI happening again?

Declare every referenced secret in the top-level secrets: block. 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
