Repository navigation
preamble emits double-quoted values for shell variables that came from quoted dotenv lines, breaking dependent apps #28
Description
Summary
The per-slug preamble at .ecluse/preambles/<slug>.sh (introduced in 0.3.0) preserves the quote characters from the source .env file when re-emitting them as shell export statements. The result is that the runtime env var contains literal quote characters as part of its value, breaking any consumer that expects the unquoted value.
This is a separate bug from #26 / #27 but compounds with #27: zsh users hit #27 first (no env loads at all), bash users would hit this quote bug as soon as the preamble actually loads.
Version / environment
- ecluse 0.3.0
process_manager = "tmux"- macOS 14, zsh and bash both affected
- mode = "hybrid"
Reproduction
Given a .env file with quoted values (the most common dotenv style):
# .env
ONYX_ENVIRONMENT="development"
E2E_TEST_EMAIL="e2e-test@example.com"
API_BASE_URL=http://localhost:4444
After ecluse up feat-foo, inspect the generated preamble:
grep -E "ONYX_ENVIRONMENT |E2E_TEST_EMAIL|API_BASE_URL" .ecluse/preambles/feat-foo.sh
# Output:
# export ONYX_ENVIRONMENT='"development"'
# export E2E_TEST_EMAIL='"e2e-test@example.com"'
# export API_BASE_URL='http://localhost:4444'Note the literal "..." double quotes inside the single quotes on the first two lines — those quotes are part of the value, not syntax. The third line is correct because the original .env line had no quotes.
When the preamble is sourced and a downstream app reads the var:
source .ecluse/preambles/feat-foo.sh
echo "ONYX_ENVIRONMENT is [$ONYX_ENVIRONMENT]"
# Output: ONYX_ENVIRONMENT is ["development"] ← includes the quotes!For example a vite plugin that validates ONYX_ENVIRONMENT against z.literal("development") will fail with:
{
"received": "\"development\"",
"code": "invalid_literal",
"expected": "development",
"message": "Invalid literal value, expected \"development\""
}
…because the value is the 13-character string "development" (with quotes), not the 11-character string development.
Root cause
The preamble generator appears to be reading the raw bytes of each line in .env, finding the =, taking everything after it as the value (including any surrounding quotes), and then wrapping that whole substring in single quotes for the export statement. Dotenv parsers normally strip the outer quotes during parse; this code path is treating dotenv syntax as if it were shell syntax (where FOO="bar" is identical to FOO=bar).
A correct implementation would either:
- Parse the
.envfile with a dotenv-compatible parser that strips outer matching quote pairs ("..."and'...') before re-serialising - Re-emit values with shell-correct quoting via
printf %q(bash) or equivalent, working from the parsed (unquoted) value, not the raw source bytes
Right now it's the worst of both worlds: values that happen to have no quotes in .env come through fine, but values that have quotes round-trip with the quotes embedded.
Suggested fix
Use a dotenv parser when reading .env / .env.local, and re-emit with shell-safe quoting from the parsed value:
// pseudocode
for (key, value) in dotenv_parse(env_file_path) {
// value already has outer quotes stripped by the parser
writeln!(preamble, "export {}={}", key, shell_escape(&value))?;
}shell_escape should wrap the value in single quotes and escape any embedded single quotes. The current logic seems to be doing roughly the second half (single-quote wrapping) but skipping the dotenv parse step.
Impact
- Severity: high once zsh: tmux startup '. <file>' fails — POSIX dot builtin doesn't search cwd in zsh, need './<file>' or 'source' #27 is fixed. Until zsh: tmux startup '. <file>' fails — POSIX dot builtin doesn't search cwd in zsh, need './<file>' or 'source' #27 lands, the preamble doesn't get sourced via the per-slot
.envchain on zsh, so this quote bug doesn't surface (apps fail earlier). After zsh: tmux startup '. <file>' fails — POSIX dot builtin doesn't search cwd in zsh, need './<file>' or 'source' #27 fixes, this becomes the blocker. - Affects: any var in
.env/.env.localthat uses the conventionalKEY="value"quoting. That's the default style in most.env.tpltemplates and the recommended way to write strings with spaces or special chars in dotenv. - Tests that validate env values against literals (zod schemas, manual
if "$FOO" = "expected"checks) will fail with mysteriously quoted values.
Followup to #26, related to #27
This issue was masked in 0.2.16 because the cd-ordering bug from #26 meant the per-slot env never loaded at all — so nobody noticed the preamble itself was malformed. Now that the preamble is the primary env source for spawned services (per the 0.3.0 design), the malformation matters.
Activity
hefgi commentedon Jun 15, 2026
Fix opened in PR #29.
parse_env_filenow strips a matched outer pair of"..."or'...'from dotenv values — standard dotenv convention. Seven regression tests cover the corner cases (unmatched quotes, inner escaped quotes, empty quoted, URL values with=/?, bare single quote char).hefgi commentedon Jun 15, 2026
Released in v0.3.1. After upgrading,
.envlines likeFOO="bar"will land in the runtime env as the 3-character stringbar(no embedded quotes). Strict consumers — e.g.z.literal("development")— now pass.