compose: `.env` with `export` Lines No Longer Works

Description of the issue

I recently upgraded Compose to 1.24.0-rc1 (build 0f3d4dda) and now Compose’s automatic parsing of my .env file fails. I keep export statements in my .env file so I can easily source it in addition to using it as a standard .env. In previous versions of Compose, this worked fine and didn’t give me any issues, however with this new update I instead get an error about spaces inside a value.

Context information (for bug reports)

Output of docker-compose version

docker-compose version 1.24.0-rc1, build 0f3d4dda

Output of docker version

Docker version 18.09.1, build 4c52b90

Output of docker-compose config (Make sure to add the relevant -f and other flags)

services:
  db:
    image: mdillon/postgis:10-alpine
    ports:
    - 5432:5432/tcp
    volumes:
    - pgdata:/var/lib/postgresql/data:rw
  elasticsearch:
    environment:
      discovery.type: single-node
    image: docker.elastic.co/elasticsearch/elasticsearch:6.1.3
  memcached:
    image: memcached:1.5.10-alpine
  redis:
    image: redis:4.0.6-alpine
  web:
    build:
      context: /Users/berwyn/dev/<repo>
    depends_on:
    - db
    - elasticsearch
    - memcached
    - redis
    environment:
      DB_HOST: db
      DB_USERNAME: postgres
      FOUNDELASTICSEARCH_URL: elasticsearch
      REDIS_CACHE_HOST: redis
      # Several more removed variables here
    ports:
    - 3000:3000/tcp
    stdin_open: true
    tty: true
    volumes:
    - /Users/berwyn/dev/<repo>:/app:rw
version: '3.0'
volumes:
  pgdata: {}

Steps to reproduce the issue

  1. Create a .env file with something like export FOO=1
  2. Attempt to run a one-off container docker-compose run --rm service bash
  3. Notice the error

Observed result

ERROR: In file ./.env: environment variable name `export FOO` may not contains whitespace.

Expected result

The container runs and FOO is correctly set in it.

Stacktrace / full error message

ERROR: In file ./.env: environment variable name `export FOO` may not contains whitespace.

Additional information

macOS 10.14.3 Docker & Friends installed using Cask (cask install docker-edge) image

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 33
  • Comments: 26 (1 by maintainers)

Commits related to this issue

Most upvoted comments

My guess is that this is a backwards-incompatible ~bug~fix that has not been announced in advance. Not a new bug.

See https://github.com/docker/compose/blob/master/CHANGELOG.md#bugfixes

The best approach would be to avoid exporting variables in .env files.

edit:typo

Not a fan of breaking people’s setup by introducing a not backwards-compatible change, and then declaring it a “feature”. If you don’t care about the export, how hard can it be to parse out the key=value pairs when reading the .env file?

Also worth noting that while ignoring these lines is acceptable. Preferred behaviour is to support leading export keyword.

Most dotenv libraries allow optional leading export keyword:

dotenv library
ruby-dotenv https://github.com/bkeepers/dotenv#usage
python-dotenv https://github.com/theskumar/python-dotenv#usages
godotenv https://github.com/joho/godotenv#usage

EDIT: nodejs dotenv libraryies don’t seem to allow export keyword?

pip install docker-compose==1.23.2

I really cannot understand the use-case of the old behavior… If someone find the misconfiguration, they should fix the configuration. If you don’t want to evaluate some lines, you could comment out these lines. That makes your intentions clearer.

@hirochachacha I’m in favour of you not breaking anyone’s setup and forcing people to change everything about their deployments just because you thought it would be a good idea to error out on lines that you can’t/won’t parse.

HTML doesn’t stop rendering because it encounters an invalid tag and this kind of logic would best apply here.

I’m in favor of https://github.com/docker/compose/issues/6741 - add command line option that can disable loading .env feature. Then, advanced people can do anything they want while docker-compose and docker can keep their simplicity and compatibility.

I was sharing a .env between compose and other, related, scripts in my repo. I needed these values to be exported for some of these scripts to work. Compose was parsing them correctly before, but now I need to keep duplicates of my .env. Feels bad.

I have a much different use-case for this, actually. As per the original comment, I like to source my .env for use with orchestration scripts. Using dotenv libraries from Ruby, Node, .NET, etc are perfectly happy to ignore the export lines and parse the rest, and previously docker-compose was also happy to do this.

Very handy to support both docker-compose up and source .env && scripts/do-some-ci-thing.sh

Is there a way to ignore the env file? Because I have an env file not to docker-compose, but to my app. And when I run docker-compose … it fails because is trying to use the env file

Please note that ruby’s dotenv recommends or allows you to store the .env file with the caveat that you do not put any sensitive information in there. Since ruby’s dotenv supports combining multiple .env files such as .env.local (which would be .gitignore’d and never committed), using .env file for general default environment variables is totally legitimate for that library.

Reference: https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use

Presumably, docker-compose’s .env format has not been supporting export syntax since day one.

https://docs.docker.com/compose/env-file/

I also checked the following test case with old docker-compose version:

$ cat .env
VAR2=2
export VAR3=3
$ cat docker-compose.yaml
version: "3"
services:
  env_test:
    image: alpine
    environment:
      - VAR1=1
      - VAR2=${VAR2}
      - VAR3=${VAR3}
    command: env
$ docker-compose up && docker-compose down
WARNING: The VAR3 variable is not set. Defaulting to a blank string.
Creating network "d_default" with the default driver
Creating d_env_test_1 ... done
Attaching to d_env_test_1
env_test_1  | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
env_test_1  | HOSTNAME=f137dd513f8f
env_test_1  | VAR1=1
env_test_1  | VAR2=2
env_test_1  | VAR3
env_test_1  | HOME=/root
d_env_test_1 exited with code 0
WARNING: The VAR3 variable is not set. Defaulting to a blank string.
Removing d_env_test_1 ... done
Removing network d_default

As you can see, export VAR3=3 line in .env wasn’t recognized by docker-compose.

I also tested source .env scenario, but I cannot see nice output:

$ cat .env
VAR2=2
export VAR3=3
$ cat docker-compose.yaml
version: "3"
services:
  env_test:
    image: alpine
    environment:
      - source .env
    command: env
$ docker-compose up && docker-compose down
Creating network "d_default" with the default driver
Creating d_env_test_1 ... done
Attaching to d_env_test_1
env_test_1  | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
env_test_1  | HOSTNAME=468523d0ef4b
env_test_1  | HOME=/root
d_env_test_1 exited with code 0
Removing d_env_test_1 ... done
Removing network d_default

So, if I understand correctly, this is not a bug.

I don’t think that we ever supported this, but moreover, it was certainly never the intent: see our docs which clearly state

Compose expects each line in an env file to be in VAR=VAL format.

This is fixed in 1.26.0-rc2 and later. 1.26.0 is not released yet.

Hallelujah! Switching to python-dotenv in #7150 solves my compatibillity issues as that’s what my target app is using to parse .env

python-dotenv has multi-line variables which is it’s in my requirements https://github.com/bkeepers/dotenv#multi-line-values

edit: It’s not in any released version yet.