2.2.1 did not actually fix #431 for everyone. If you are on Symfony 7.0, 7.1, 7.2 or 7.3, or on a patch of 6.4 older than 6.4.37 or of 8.0 older than 8.0.9, upgrade to this instead.
What 2.2.1 got wrong
The check on ttl was moved from a validate() closure to min(), because NumericNode skips min() while it is handling the placeholder an environment variable stands in as.
It does — in symfony/config 6.4.37, 7.4.9, 8.0.9 and 8.1 onwards. That skip was backported to the maintained branches only, and 7.0 through 7.3 are end of life, so they never received it and never will. On any of those, 2.2.1 rejected %env(int:...)% exactly as 2.2.0 did.
What this does
Neither ttl nor max_tokens_per_user is validated in the configuration tree any more.
On the affected versions there is no check that can tell the sample value of 0 — which Symfony substitutes to see whether the configuration would accept the variable — from a 0 written by hand. Refusing to boot an application that reads its ttl from the environment is the worse of the two failures, so the check is gone rather than made conditional.
A ttl of 0 or less is therefore accepted again, as it was in 2.1.0 and earlier. It still produces a token that has expired by the time it is handed over, so it is worth not writing one.
gesdinet_jwt_refresh_token:
ttl: '%env(int:JWT_REFRESH_TOKEN_LIFETIME_IN_SECONDS)%'works on every Symfony this release supports.