Skip to content

fix: accept a FIFO .env file in dotenv run - #723

Open
sungbin1015 wants to merge 1 commit into
theskumar:mainfrom
sungbin1015:fix-run-fifo
Open

sungbin1015 wants to merge 1 commit into
theskumar:mainfrom
sungbin1015:fix-run-fifo

Conversation

@sungbin1015

@sungbin1015 sungbin1015 commented Oct 6, 2026 •

Copy link
Copy Markdown

Problem

dotenv run rejects a .env path that is a FIFO, although the library (load_dotenv, dotenv_values, find_dotenv, since #586) and the list/get subcommands read it fine:

$ dotenv -f <(echo A=1) list
A=1
$ dotenv -f <(echo A=1) get A
1
$ dotenv -f <(echo A=1) run printenv A
Usage: dotenv run [OPTIONS] [COMMANDLINE]...
Try 'dotenv run --help' for help.

Error: Invalid value: Invalid value for '-f' "/dev/fd/63" does not exist.

The same happens with a named pipe created by mkfifo and picked up as the default ./.env, which is the 1Password-mounted .env case #586 was written for: load_dotenv() works there, dotenv run -- cmd does not.

Cause

run guards the path with os.path.isfile(file) before handing it to DotEnv. DotEnv._get_stream and find_dotenv use _is_file_or_fifo instead; the guard in cli.py was not updated when FIFO support was added.

Fix

Use _is_file_or_fifo in the run guard. Missing paths and directories are still rejected with the same message. No change on Windows, where _is_file_or_fifo is equivalent to os.path.isfile.

Tests

  • tests/test_fifo_dotenv.py::test_cli_run_from_fifo (Unix only, like the existing FIFO test): fails before the change with the error above, passes after.
  • pytest: 285 passed, 4 skipped. ruff check src tests, ruff format --check src tests and mypy for 3.10-3.14 are clean.

Related work

`dotenv run` guarded the path with `os.path.isfile`, so a `.env` that is a
named pipe (1Password-mounted `.env`, `<(...)` process substitution) was
rejected with "does not exist", while `load_dotenv` and `dotenv list`/`get`
read it. Use `_is_file_or_fifo`, as `DotEnv._get_stream` and `find_dotenv` do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Riccardo-Vecchi

Copy link
Copy Markdown

Independent Linux validation of 92216393627596e62e7e7cf6152a43d33c64db63 (OpenAI Codex-assisted).

A private subprocess matrix uses real os.mkfifo pipes and the actual python -m dotenv run entry point, with synthetic values and a five-second timeout per command:

  • default and explicit FIFO paths, a symlink to a FIFO, and a producer delayed by 200 ms;
  • --no-override preserving a parent value and --override replacing it;
  • child exit status 7, a multiline UTF-8 value, and Bash <(...) process substitution;
  • regular-file success, missing-path rejection and directory rejection as controls.

On unchanged base 0b2880591780a426b0551436f47a17e7a76d954f, all nine FIFO cases return the existing exit-2 error; the three controls pass. On this PR head, 12/12 pass. Writers use bounded nonblocking opens and are joined, so a rejection cannot leave a blocked producer behind.

CPython 3.12.3: the repository suite passes 289 tests on the PR, versus 288 on the base. Both runs emit the same 35 warnings (Click's isolated-filesystem deprecation and IPython's temporary-directory fallback). Ruff check/format and mypy targets 3.10–3.14 pass; those mypy targets are static checks, not runs on five interpreters. The checkout is unchanged.

This validates the POSIX CLI/FIFO path and environment/exit-code behavior. It does not establish compatibility with a real 1Password mount, macOS or Windows.

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.

2 participants