Honor populated variables before dotenv defaults in ConfigProvider - #6938
Honor populated variables before dotenv defaults in ConfigProvider#6938fubhy wants to merge 1 commit into
Conversation
|
There was a problem hiding this comment.
Important
The reproduction test is accurate, but the implementation fix described in the PR body is missing, so this PR cannot merge as-is.
Reviewed changes
This PR adds a new test file, packages/effect/test/ConfigProviderDotEnvDefault.test.ts, containing one regression test that demonstrates the dotenv expansion precedence bug: ${SET:-fallback} resolves to fallback when SET is populated.
- Verified the new test fails against
mainwith the expected error (value: 'fallback'received,value: 'actual'expected). - The implementation change shown in the PR body as required has not been committed yet.
⚠️ Implementation fix is missing
The bug is in packages/effect/src/ConfigProvider.ts:1101. The current replacement:
envValue.replace(group, defaultValue || (Object.hasOwn(parsed, variableName) ? parsed[variableName] : ""))evaluates defaultValue first, so any non-empty default wins before the variable is consulted. Per dotenv/dotenv-expand semantics, ${NAME:-fallback} should use NAME when populated and fallback only when NAME is unset or empty.
Please add the implementation change. A minimal fix is:
const value = Object.hasOwn(parsed, variableName) && parsed[variableName] !== ""
? parsed[variableName]
: defaultValue ?? ""
envValue.replace(group, value)ℹ️ Nitpicks
- Consider adding two more cases to the new test file: an unset variable (
${UNSET:-fallback}) and an empty variable (${EMPTY:-fallback}). This would fully specify the fallback behavior and guard against a partial implementation. - A dedicated test file is fine, but these assertions could also live in the existing
ConfigProviderdotenv expansiondescribeblock; either location is acceptable.
@v0 or keep the SHA fresh with Dependabot | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏
| yield* provider.load(["DEFAULTED"]), | ||
| ConfigProvider.makeValue("actual") | ||
| ) | ||
| })) |
There was a problem hiding this comment.
Consider adding cases for an unset variable (${UNSET:-fallback}) and an empty variable (${EMPTY:-fallback}) so the fallback side of the ${...:-...} semantics is also specified.

Summary
With variable expansion enabled, ${SET:-fallback} resolves to fallback even when SET contains actual.
Important
This PR starts with focused failing reproduction tests. Add the implementation fix to this same branch; CI is expected to fail until that fix is included.
Dotenv default overrides a populated variable
Module:
ConfigProviderAudit ID:
core-a-f-config-provider-dotenv-default-precedenceSeverity / confidence: medium / high
What happens
With variable expansion enabled, ${SET:-fallback} resolves to fallback even when SET contains actual.
Why it happens
interpolate replaces the match with defaultValue || parsed[variableName], so every non-empty default wins before the referenced variable is checked.
Expected behavior
Dotenv expansion follows dotenv and dotenv-expand semantics: ${NAME:-fallback} uses NAME when populated and fallback only when the variable is unset or empty.
Relevant implementation
These links and excerpts are pinned to audit base
c9b56ab507f224426ee8388dc450da447ec4715f.packages/effect/src/ConfigProvider.ts:1071-1103packages/effect/src/ConfigProvider.ts:1101View problematic code at
packages/effect/src/ConfigProvider.ts:1071-1103View exact lines on GitHub
View problematic code at
packages/effect/src/ConfigProvider.ts:1101View exact lines on GitHub
Reproduction
pnpm test --run packages/effect/test/ConfigProviderDotEnvDefault.test.tsObserved failure: The provider loaded fallback instead of actual.
Implementation handoff
The initial reproduction tests on this branch are the regression specification for the implementation fix that should follow in this PR.
pnpm test --run packages/effect/test/ConfigProviderDotEnvDefault.test.tsAudit provenance
c9b56ab507f224426ee8388dc450da447ec4715fc9b56ab507f224426ee8388dc450da447ec4715fcore-a-f-config-provider-dotenv-default-precedence