validating ...\q1\compose.yaml: volumes must be a mapping means the top-level volumes: block lists the volume names with dashes, as in - appdata. Compose wants each name as a key. Write appdata: with a colon and no dash.

The message names volumes with no service in front of it, so it is the block at the bottom of the file, not the volumes list inside a service. Inside a service the list with dashes is the right shape.

The error

PS> docker compose -f compose.yaml config
validating ...\q1\compose.yaml: volumes must be a mapping

The file (the long path in the message is shortened above):

name: fix10-cy-q1
services:
  web:
    image: alpine
    command: ["sleep", "1"]
    volumes:
      - appdata:/data
volumes:
  - appdata

Why it happens

The two volumes keys in a Compose file have different shapes. Under a service it is a list of mounts, one per dash line, and - appdata:/data is correct there. At the top level it declares named volumes, and each name is a key whose value holds that volume's options, even when there are none. A dash makes the block a list, and Compose refuses it with the message above, which names the top-level block but gives no line number for it.

Copying the service's list style down to the top-level block is the easy way to make this mistake, since both blocks hold the same name and sit only a few lines apart.

The fix

name: fix10-cy-q1
services:
  web:
    image: alpine
    command: ["sleep", "1"]
    volumes:
      - appdata:/data
volumes:
  appdata:
PS> docker compose -f compose.fixed.yaml config
...
volumes:
  appdata:
    name: fix10-cy-q1_appdata

appdata: with nothing after the colon is a key with an empty value, and that is enough: config shows the volume with the name Compose will give it, the project name plus _appdata, and the service's mount appdata:/data refers to that declared volume.

How it was reproduced

Docker Desktop on Windows 11, Docker Compose v5.7.0, engine 29.9.3, Windows PowerShell 5.1. A one-service compose.yaml with a top-level volumes: block written as - appdata gave the message above on docker compose -f compose.yaml config with exit code 1; with appdata: the same command printed the model with exit code 0. No container or volume was created. The project name fix10-cy-q1 is the test's own.

Frequently asked

What does volumes must be a mapping mean in docker compose?
The top-level volumes block was written as a list with dashes. Write each volume name as a key, appdata: with a colon, and no dash.
How do I declare a named volume in compose.yaml?
Under a top-level volumes: key, write the name followed by a colon, such as appdata:. In the test config then showed it as fix10-cy-q1_appdata.
Why does the service volumes list use dashes but the top-level one does not?
Under a service, volumes is a list of mounts. At the top level it is a mapping from volume names to their options, and a list is refused there.

More decoded errors in the Fixes category. The same kind of message for one service's list is covered in depends_on must be a array.