Invalid interpolation format into docker compose file

$ cat 1.yml 
services:
    composer:
        image: composer/composer
        volumes:
            - ${COMPOSER_HOME:-$HOME/.config/composer}:/tmp

$ cat 2.yml 
services:
    workaround:
        extends:
            file: 1.yml
            service: composer

Let’s do some tests

$ docker compose -f 2.yml config
invalid interpolation format for services.workaround.volumes.[].source.
You may need to escape any $ with another $.
${COMPOSER_HOME

$ docker compose -f 1.yml config
name: tmprzkaunqtkf
services:
  composer:
    image: composer/composer
blabla...

Summing up

$ docker compose -f 2.yml config # not works
$ docker compose -f 1.yml config # works

Why?

To avoid interpolating $HOME, do $$HOME

As for how the variables are interpolated, when extending a service, the interpolated variables will be taken from the extending (not extended) file’s directory

Meaning, if you have 1.yml and 2.yml in different directories, they will interpolate the variables from different .env files

Currently, your files are in the same directory, but keep ti in mind in case you change your folder structure

$ cat 1.yml 
services:
    composer:
        image: composer/composer
        volumes:
            - $${COMPOSER_HOME:-$$HOME/.config/composer}:/tmp

$ docker compose -f 2.yml config
service "workaround" refers to undefined volume ${COMPOSER_HOME: invalid compose project

${COMPOSER_HOME:-$$HOME/.config/compose}:/tmp

One dollar before COMPOSER_HOME so it is interpolated from .env
Two dollars before HOME so that it literally uses the string $HOME

$ cat 1.yml 
services:
    composer:
        image: composer/composer
        volumes:
            - ${COMPOSER_HOME:-$$HOME/.config/composer}:/tmp

$ docker compose -f 2.yml config
invalid interpolation format for services.workaround.volumes.[].source.
You may need to escape any $ with another $.
${COMPOSER_HOME

Actually, now that I’m running the code on my computer

I was wrong with the first answer, the single $ is correct, both are interpolated variables

As for the error you’re experiencing, unfortunately, I was able to successfully run the first version of your files, as you uploaded them initially, and it worked

So why doesn’t it work for me?

Are the files in the same directory or is this a reduced version of them?

$ tree -a
├── 1.yml
└── 2.yml

$ cat 1.yml 
services:
    composer:
        image: composer/composer
        volumes:
            - ${COMPOSER_HOME:-$HOME/.config/composer}:/tmp

$ cat 2.yml 
services:
    workaround:
        extends:
            file: 1.yml
            service: composer

$ docker compose -f 2.yml config
invalid interpolation format for services.workaround.volumes.[].source.
You may need to escape any $ with another $.
${COMPOSER_HOME

Nothing???

Since we could not reproduce it (I tried too), there must be something different on your end.

Maybe a wrong version of docker compose. My version: v2.28.1-desktop.1
Or maybe the variables contain a special value that we haven’t tried.

You can also triy this:

docker compose -f 2.yml config --no-interpolate

which will not interpolate variables so the variable references will be kept in the output. That shows me that something is wrong with the output

name: test
networks:
  default:
    name: test_default
services:
  workaround:
    image: composer/composer
    networks:
      default: null
    volumes:
      - source: ${COMPOSER_HOME
        target: -$HOME/.config/composer}
        type: volume
        volume: {}

Which shows something similar to what you see in your error message

      - source: ${COMPOSER_HOME

Which is an invalid reference. The colon separates the source and the target but your syntax uses a colon which is interestingly interpreted well on my machine but not when I use this no-interpolate flag. I guess there was a bug which was fixed in my version but still gives an invalid output with the flag. So you can use the long syntax in 1.yml

services:
    composer:
        image: composer/composer
        volumes:
            - type: bind
              source: ${COMPOSER_HOME:-$HOME/.config/composer}
              target: /tmp

Even with this syntax, the no-interpolate flag wil result an incorrect output, but I remember that is an old issue which I attempted to fix as well when I tried to contribute in the compose code but seemed hard to fix. The final output without the flag should be correct though.

1 Like

First of all

+ docker compose version
Docker Compose version v2.29.0

My scenario

+ cat 1.yml
services:
    composer:
        image: composer/composer
        volumes:
            - type: bind
              source: ${COMPOSER_HOME:-$HOME/.config/composer}
              target: /tmp

+ cat 2.yml
services:
    workaround:
        extends:
            file: 1.yml
            service: composer

Let’s try

+ docker compose -f 2.yml config
services:
  workaround:
    image: composer/composer
    volumes:
      - type: bind
        source: HOME/.config/composer
        target: /tmp

It seems the long syntax works!!!

Is $COMPOSER_HOME set to ‘HOME’? If it’s empty, then $HOME should be interpolated as the path to your home folder, is it working?

Not sure what was causing the issues as the syntax was correct initially, but if it works now then I’m glad

$ echo ${COMPOSER_HOME:-Not set}
Not set

yes

Then it is also possible that they introduced a new bug, but I recommend using the long syntax anyway. That way you can make sure it will not create a new folder when you accidentally set a wrong filepath or folder path as source. That behavior can be enabled optionally, but by default it refuses to create the project if the source does not exist.

Which behavior?

???

The behavior to create the folder automatically even when using the long syntax. I don’t know any reason to do so, but it is possible.

https://docs.docker.com/compose/compose-file/05-services/#long-syntax-5

bind: Used to configure additional bind options:
  create_host_path: Creates a directory at the source path on host if there is nothing present. Compose does 
  nothing if there is something present at the path. This is automatically implied by short syntax for backward compatibility with docker-compose legacy.
`

mmmhhh … however you are talking about an aspect that may perhaps be interested, but not in this discussion

It was related to the changed syntax from short to long so whether it matters to you or not, could be important to know for anyone who visits this topic. And I wrote it as a reply to your version number and the fact that maybe this bug was introduced in that version. If it is true, even if it is fixed in the future, it is better to keep the long syntax.