Skip to content

Commit bca6644

Browse files
h1whelanclaudetheskumar
authored
fix: strip UTF-8 BOM from .env files (#640)
* Fix: strip UTF-8 BOM from .env files to prevent silent first-variable loss When a .env file is saved with a UTF-8 BOM (common with JetBrains IDEs on Windows), the BOM character (\ufeff) was prepended to the first variable name, making it silently inaccessible via its intended key. Strip the BOM in Reader.__init__ so all variables are parsed correctly regardless of whether the file contains a BOM. Fixes #637 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add changelog entry for BOM fix --------- Co-authored-by: h1whelan <h1whelan@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Saurabh Kumar <theskumar@users.noreply.github.com>
1 parent 68ea2d1 commit bca6644

3 files changed

Lines changed: 35 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
99

10-
- ...
10+
### Fixed
11+
12+
- Strip a leading UTF-8 BOM from `.env` file contents so the first variable is no longer silently lost when the file is saved with BOM (e.g. by some JetBrains IDEs on Windows) by [@h1whelan] in [#640]
1113

1214
## [1.2.2] - 2026-03-01
1315

@@ -432,6 +434,7 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
432434
[#563]: https://github.com/theskumar/python-dotenv/pull/563
433435
[#497]: https://github.com/theskumar/python-dotenv/pull/497
434436
[#161]: https://github.com/theskumar/python-dotenv/issues/161
437+
[#640]: https://github.com/theskumar/python-dotenv/pull/640
435438
[790c5c0]: https://github.com/theskumar/python-dotenv/commit/790c5c02991100aa1bf41ee5330aca75edc51311
436439

437440
<!-- contributors -->
@@ -460,6 +463,7 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
460463
[@gergelyk]: https://github.com/gergelyk
461464
[@gongqingkui]: https://github.com/gongqingkui
462465
[@greyli]: https://github.com/greyli
466+
[@h1whelan]: https://github.com/h1whelan
463467
[@harveer07]: https://github.com/harveer07
464468
[@jadutter]: https://github.com/jadutter
465469
[@jankislinger]: https://github.com/jankislinger

src/dotenv/parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class Error(Exception):
6868

6969
class Reader:
7070
def __init__(self, stream: IO[str]) -> None:
71-
self.string = stream.read()
71+
self.string = stream.read().removeprefix("\ufeff")
7272
self.position = Position.start()
7373
self.mark = Position.start()
7474

tests/test_parser.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,35 @@
545545
),
546546
],
547547
),
548+
# UTF-8 BOM at the start of the file should be stripped
549+
(
550+
"\ufeffa=b",
551+
[
552+
Binding(
553+
key="a",
554+
value="b",
555+
original=Original(string="a=b", line=1),
556+
error=False,
557+
)
558+
],
559+
),
560+
(
561+
"\ufeffa=b\nc=d",
562+
[
563+
Binding(
564+
key="a",
565+
value="b",
566+
original=Original(string="a=b\n", line=1),
567+
error=False,
568+
),
569+
Binding(
570+
key="c",
571+
value="d",
572+
original=Original(string="c=d", line=2),
573+
error=False,
574+
),
575+
],
576+
),
548577
],
549578
)
550579
def test_parse_stream(test_input, expected):

0 commit comments

Comments
 (0)