invalid spec: :/data: empty section between colons means a volume line in your Compose file has nothing before the first colon: the source of the mount is missing. Put a host path or a volume name in front, as in appdata:/data.

Its sibling, invalid spec: ./a:/b:ro:extra: too many colons, came from an entry with four parts; the same entry with three parts was accepted. Both messages quote the whole entry, so search for it in the service's volumes list.

The error

PS> docker compose -f compose.yaml config
invalid spec: :/data: empty section between colons

The file:

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

The same list with - "./a:/b:ro:extra" as its entry:

PS> docker compose -f compose.colons.yaml config
invalid spec: ./a:/b:ro:extra: too many colons

Why it happens

In ":/data" nothing stands before the first colon, so the entry names no source, and the message says the section is empty. "./a:/b:ro:extra" has four parts separated by colons, and Compose refused the whole entry as having too many. In the fixed file, "./a:/b:ro" with three parts was accepted and shown as a bind mount with read_only: true, and appdata:/data with two parts as a named volume. Both broken files failed on config with exit code 1.

Neither message gives a file or a line number, only the entry itself. When a service has several volume lines, compare each with the quoted text; the colons are what to count.

The fix

name: fix10-cy-q9
services:
  web:
    image: alpine
    command: ["sleep", "1"]
    volumes:
      - "./a:/b:ro"
      - appdata:/data
volumes:
  appdata:
PS> docker compose -f compose.fixed.yaml config
...
      - type: bind
        source: C:\...\q9\a
        target: /b
        read_only: true
...
      - type: volume
        source: appdata
        target: /data
...

"./a:/b:ro" keeps three parts, a bind mount of the folder a next to the Compose file, read-only, and appdata:/data gives the second mount a named volume as its source, declared in the top-level volumes block. The file validates and config prints both mounts in their long form: the bind source resolved to a full path (shortened above) with read_only: true, and the volume by name.

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 the volume ":/data", and a copy with "./a:/b:ro:extra", gave the two messages above on docker compose -f ... config with exit code 1; the corrected file printed the model with exit code 0. No container or volume was created. The project name fix10-cy-q9 is the test's own.

Frequently asked

What does invalid spec empty section between colons mean in docker compose?
A short volume entry has an empty part, such as :/data with no source before the colon. Put a host path or volume name in front.
What does invalid spec too many colons mean?
The short volume entry has too many parts. In the test the four-part ./a:/b:ro:extra was refused; the three-part ./a:/b:ro was accepted.
How do I mount a volume read-only in docker compose?
Add :ro as the third part, as in ./a:/b:ro. In the test that entry validated with config.

More decoded errors in the Fixes category. A Windows path in a volume line can fail earlier, in the YAML itself; see found unknown escape character.