When using Symfony inside a container, %env(csv:...)%
seems to break when populating a config option that expects an array. For example, in config/packages/framework.yaml
:
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
trusted_proxies: '%env(string:APP_TRUSTED_PROXIES)%'
trusted_headers: '%env(csv:APP_TRUSTED_HEADERS)%'
Because .env files are not read in my containerized setup, I set APP_TRUSTED_HEADERS via Docker Compose as a comma-separated string.
Running:
docker compose exec php php bin/console debug:container --env-vars | grep APP_
I get:
In BaseNode.php line 496:
Invalid type for path "framework.trusted_headers.0". Expected one of "bool"
, "int", "float", "string", but got "array".
trusted_headers
expects an array<int, int|bool|string>
, but Symfony complains it receives an array<int, array>
.
How to reproduce? Start a new Symfony app in Docker (I used the FrankenPHP image from symfony-docker):
git clone https://github.com/dunglas/symfony-docker
cd symfony-docker
docker compose build --pull --no-cache
docker compose up --wait
Then edit the config/packages/framework.yaml and add:
framework:
trusted_headers: '%env(csv:APP_TRUSTED_HEADERS)%'
In compose.yaml, define the env var. I tried the following (each variant tested separately):
service:
php:
environment:
APP_TRUSTED_HEADERS: forwarded,x-forward-port # does NOT WORK
APP_TRUSTED_HEADERS: forwarded # does NOT WORK
APP_TRUSTED_HEADERS: "forwarded" # does NOT WORK
APP_TRUSTED_HEADERS: "'forwarded'" # does NOT WORK
APP_TRUSTED_HEADERS: "${APP_TRUSTED_HEADERS}" # with the host env set
All variants result in the same error. I read "Environment variable processors", this post about "Environment variables in a dockerized Symfony" and How to Configure Symfony to Work behind a Load Balancer or a Reverse Proxy
What am I doing wrong, and how should APP_TRUSTED_HEADERS be passed so that %env(csv:...)%
resolves to a flat array of strings?
Note on possible duplicates
I’ve read "docker-compose variable substitution/interpolation with list/map or array values?" and I believe this is not a duplicate: I’m not trying to pass an array via Compose.
I’m intentionally passing a single comma-separated string (e.g., forwarded,x-forwarded-for,...) and relying on Symfony’s %env(csv:VAR)% processor to parse it at runtime. The problem is that, even with a plain string in the container env, Symfony ends up treating framework.trusted_headers.0 as an array (i.e., array). So this question is about Symfony/Dotenv CSV processing in a containerized setup, not Compose array interpolation.
3 Answers 3
The /framework/trusted_headers
is always treated as a plain scalar, even if properly tagged as sequence.
What happens is, that Symfony renders it as the first member of the sequence then, e.g.:
framework:
trusted_headers: XXX
effectively becomes:
framework:
trusted_headers:
- XXX
This is also the reason why the schema validation reports an array on the first member of the sequence with the built-in environment variable processor that decoded the environment parameter value into an array:
Invalid type for path "framework.trusted_headers.0". Expected one of "bool" , "int", "float", "string", but got "array".
This is now an array inside an array. From the Symfony configuration guidelines you have to put the array into the YAML file.
The single test on the trusted_headers
configuration setting is limited to a single only for SYMFONY_TRUSTED_HEADERS
(#58161), the underlying parameter and the latest step towards featuring the environment.
I found a solution with the new simpler trusted proxies configuration .
In Symfony 7.2 we're simplifying this thanks to new environment variables. Instead of configuring the previous file, you can now set the trusted proxies configuration in these env vars:
SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER
SYMFONY_TRUSTED_HEADERS
SYMFONY_TRUSTED_HOSTS
SYMFONY_TRUSTED_PROXIES
So I removed the two configuration lines in my framework.yaml
file.
framework.yaml is empty, so the default configuration is applied:
framework:
trusted_proxies: '%env(default:SYMFONY_TRUSTED_PROXIES)%'
trusted_headers: '%env(default:SYMFONY_TRUSTED_HEADERS)%'
And I updated my compose.<environment>.yaml files
# compose.test.yaml
services:
php:
environment:
# All private subnets are trusted in test environment
SYMFONY_TRUSTED_PROXIES: PRIVATE_SUBNETS
SYMFONY_TRUSTED_HEADERS: x-forwarded-host,x-forwarded-proto,x-forwarded-port
# compose.dev.yaml
services:
php:
environment:
SYMFONY_TRUSTED_PROXIES:
SYMFONY_TRUSTED_HEADERS:
# compose.prod.yaml
services:
php:
environment:
SYMFONY_TRUSTED_PROXIES: 172.16.0.xxx # The IP of your reverse-proxy
SYMFONY_TRUSTED_HEADERS: x-forwarded-host,x-forwarded-proto,x-forwarded-port
-
If that was the answer, then please review the question and my answer as I pointed to
SYMFONY_TRUSTED_HEADERS
specifically. Didn't dv btw, but you should give credit where credit is due. If you think otherwise, feedback appreciated.hakre– hakre2025年09月06日 05:27:09 +00:00Commented yesterday
The issue comes from how Docker/YAML handles quotes. Symfony’s %env(csv:...)%
expects a plain comma separated string, but if you add quotes or extra characters, it sees each element as an array instead of a string. That’s why you get the Invalid type for path "framework.trusted_headers.0"
error.
In your docker-compose.yml
, pass the environment variable without the quotes:
services:
php:
environment:
APP_TRUSTED_HEADERS: forwarded,x-forwarded-for,client-ip
In your framework.yaml
, use the CSV processor like this:
framework:
trusted_proxies: '%env(string:APP_TRUSTED_PROXIES)%'
trusted_headers: '%env(csv:APP_TRUSTED_HEADERS)%'
And then check inside the container:
docker compose exec php bash
echo $APP_TRUSTED_HEADERS
php bin/console debug:container --env-vars | grep APP_TRUSTED_HEADERS
You should see a flat string, and Symfony will correctly convert it into an array.
-
1Do you have any resource about how Docker/YAML handles quotes like that ? I tried to test it but I always get a plain string value, and OP already tried defining the value without quotes (see his first attempt on the list).AymDev– AymDev2025年09月02日 08:30:30 +00:00Commented Sep 2 at 8:30
-
1I'm sorry, but This is exactly what I've done! And Symfony doesn't convert it correctly ! (And your solution is exactly what I've described in my first test. Does it really work with your environment?Alexandre Tranchant– Alexandre Tranchant2025年09月02日 09:16:14 +00:00Commented Sep 2 at 9:16
-
1And yet, the question mentions they use your proposed solution, and they claim it does not work. Why don't you address this on the answer?yivi– yivi2025年09月02日 09:37:44 +00:00Commented Sep 2 at 9:37
docker compose exec php env | grep APP_TRUSTED_HEADERS
to check the value ofAPP_TRUSTED_HEADERS
, to ensure that it is passed properly to the container.