Skip to content

Don't rewrite the .env file when unset_key finds no such key - #734

Open
PDGGK wants to merge 2 commits into
theskumar:mainfrom
PDGGK:fix-unset-missing-key-no-rewrite
Open

PDGGK wants to merge 2 commits into
theskumar:mainfrom
PDGGK:fix-unset-missing-key-no-rewrite

Conversation

@PDGGK

@PDGGK PDGGK commented Oct 20, 2026

Copy link
Copy Markdown

When the key isn't in the file, unset_key (and dotenv unset) correctly returns (None, key) / exits with 1 and "key doesn't exist", but by then it has already replaced the file through rewrite(). A no-op unset therefore:

  • turns a symlinked .env into a regular file (and the new file has mode 0600),
  • converts CRLF line endings to LF,
  • gives the file a new inode.

For example, with app/.env -> ../shared/.env and shared/.env containing DB_HOST=localhost\r\nDB_PORT=5432\r\n, using python-dotenv 1.2.4:

$ cd app && dotenv unset DB_PASSWORD
Key DB_PASSWORD not removed from .../app/.env - key doesn't exist.
$ ls -l .env
-rw-------  ...  .env
$ od -c .env | head -2
0000000    D   B   _   H   O   S   T   =   l   o   c   a   l   h   o   s
0000020    t  \n   D   B   _   P   O   R   T   =   5   4   3   2  \n

After this, a deploy script doing dotenv unset OLD_KEY || true silently cuts the link to the shared file.

The fix abandons the rewrite when nothing was removed: rewrite() already discards its temporary file and leaves the original untouched when the body raises, so the file is read and parsed once, as before, and the warning and return value are unchanged.

Added two tests: one checks that a CRLF file keeps its bytes and inode, the other that a symlink stays a symlink (skipped on Windows like the existing symlink tests). Both fail without the change.

This branch has not been deployed

No deployments
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.

1 participant