Skip to content

Let python-dotenv be the only reader of .env - #21

Merged
Isma-L154 merged 1 commit into
mainfrom
fix/single-env-parser
Aug 21, 2026
Merged

Let python-dotenv be the only reader of .env#21
Isma-L154 merged 1 commit into
mainfrom
fix/single-env-parser

Conversation

@Isma-L154

Copy link
Copy Markdown
Owner

Closes #19

The problem

.env was parsed by two things with different rules:

  • systemd, via EnvironmentFile= in the loopify-bot unit
  • python-dotenv, via load_dotenv() in config.py

They disagree about quoting, inline comments, and values containing #, spaces or =.

The live host logs the disagreement on every single start:

loopify-bot.service: Ignoring invalid environment assignment '<a URL>': /home/ubuntu/LoopifyBot/.env

Harmless in that instance — the line is not a required variable — but it is the same file diverging between the two readers, in production, right now.

Why it matters

A token containing a # gets truncated by one parser and not the other. The bot then fails to authenticate, and the symptom looks like a bad credential rather than a parsing problem — which is a genuinely unpleasant thing to chase, especially since you cannot paste the token anywhere to compare.

The fix

python-dotenv owns the file. EnvironmentFile= is dropped from the unit, with a comment saying why so nobody adds it back as an obvious-looking improvement.

The path is also anchored to the project root rather than left to search upward from the working directory:

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
load_dotenv(os.path.join(PROJECT_ROOT, ".env"))

Otherwise the bot picks up a different file depending on where it was started from — systemd sets WorkingDirectory, but a shell invocation from anywhere else does not.

.env.example now states the rules, including the one that actually bites people: a trailing comment after a value is part of the value.

Nothing is lost by removing it

load_dotenv() writes into os.environ, so subprocesses (yt-dlp) inherit the same variables they did before. The unit's own Environment= lines for XDG_CACHE_HOME and DENO_DIR are unaffected, and load_dotenv does not override already-set variables, so they still win.

Verification

232 passed. Two new tests, both non-vacuous:

  • .env resolution is anchored to the project root.
  • deploy/setup.sh declares no active EnvironmentFile line. The check filters out commented lines, so the explanatory comment does not make it pass trivially — re-adding the directive fails the suite.

To confirm after deploy, the warning should be gone from a fresh start:

sudo journalctl -u loopify-bot --since "-2 min" | grep -i "invalid environment"

The file was parsed twice with different rules: by systemd via EnvironmentFile
and by python-dotenv via load_dotenv. They disagree about quoting, inline
comments, and values containing # or spaces. The live host logged systemd
rejecting a line the bot read fine, on every start.

The failure mode this sets up is nasty: a token containing a # would be
truncated by one parser and not the other, and the result looks like a bad
credential rather than a parsing problem.

Drop EnvironmentFile from the unit and leave python-dotenv in charge. Anchor
the path to the project root instead of searching upward from the working
directory, so the same file is used whether the bot is started by systemd, from
a shell anywhere, or by the test runner. Document the syntax rules in
.env.example, including that trailing comments after a value are not stripped.

Closes #19
@Isma-L154
Isma-L154 merged commit 823d13c into main Aug 21, 2026
3 checks passed
@Isma-L154
Isma-L154 deleted the fix/single-env-parser branch August 21, 2026 02:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The .env file is parsed by both systemd and python-dotenv, which can disagree

1 participant