Skip to content

Pytest tmpdir crashes on Python 3.13+/Windows when no username env vars are set (getpass.getuser now raises OSError) #13835

@Stefanhg

Description

@Stefanhg

Bug report generated by co-pilot EXCEPT me having to edit a bunch since it was confusing and too much blabbing:

Summary:
On Python 3.13 and 3.14 (RC) under Windows, pytest fails early with OSError: No username set in the environment if none of LOGNAME, USER, LNAME, USERNAME are present. The failure originates in _pytest/tmpdir.get_user(), which only catches ImportError and KeyError, but Python 3.13 changed getpass.getuser() to raise OSError when no username can be derived. This was previously tolerated.

Environment:

  • OS: Windows 10/11 (64-bit)
  • Python: 3.13.0 / 3.14.0rc3 (installed via uv python install 3.13 3.14)
  • Pytest: 7.4.3 (also reproduced with latest 7.x)
  • Invocation context: Subprocess without username env vars (custom runner; uv seems to sanitize environment)

Relevant Python change:
Per Python 3.13 getpass.py (getuser docstring): Behavior changed to consistently raise OSError when no environment user identifiers exist and pwd (Unix-only) is not available.
Observed Error (truncated): OSError: No username set in the environment File .../Lib/getpass.py:236, in getuser raise OSError('No username set in the environment') from e

Pytest stack location: _in _pytest/tmpdir.py: get_user() calls getpass.getuser() without handling OSError.

Minimal Reproduction (Windows, Python 3.13+):
Create a clean directory with a trivial test file:

echo "def test_ok(): pass" > test_sample.py

Launch Python with some variables cleared:

  • LOGNAME, USER, LNAME, USERNAME all set to ""

Execute:
python -c "import os, subprocess; [os.environ.pop(v,None) for v in ['LOGNAME','USER','LNAME','USERNAME']]; import pytest; raise SystemExit(pytest.main(['-q']))"

Result:
pytest crashes with OSError before collection finishes.

    def getuser():
        """Get the username from the environment or password database.

        First try various environment variables, then the password
        database.  This works on Windows as long as USERNAME is set.
        Any failure to find a username raises OSError.

        .. versionchanged:: 3.13
            Previously, various exceptions beyond just :exc:`OSError`
            were raised.
        """

        for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
            user = os.environ.get(name)
            if user:
                return user

        try:
>           import pwd
E           ModuleNotFoundError: No module named 'pwd'

C:\Users\shg\AppData\Roaming\uv\python\cpython-3.13.5-windows-x86_64-none\Lib\getpass.py:172: ModuleNotFoundError

The above exception was the direct cause of the following exception:

    def getuser():
        """Get the username from the environment or password database.

        First try various environment variables, then the password
        database.  This works on Windows as long as USERNAME is set.
        Any failure to find a username raises OSError.

        .. versionchanged:: 3.13
            Previously, various exceptions beyond just :exc:`OSError`
            were raised.
        """

        for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
            user = os.environ.get(name)
            if user:
                return user

        try:
            import pwd
            return pwd.getpwuid(os.getuid())[0]
        except (ImportError, KeyError) as e:
>           raise OSError('No username set in the environment') from e
E           OSError: No username set in the environment

Actual: Session aborts with uncaught OSError.

Root Cause:
Python 3.13 tighten semantics:
getpass.getuser() now raises OSError when no identifier found. Pytest’s get_user only catches ImportError and KeyError: except (ImportError, KeyError): return None Missing OSError handling lets the exception propagate.
Proposed Fix: Expand exception clause to include OSError.

Rationale:

Restores pre-3.13 resilient behavior.

Narrow catch still specific to getpass failure modes; avoids masking unrelated errors.
Workaround (for users now): Set an env var before running pytest

e.g. in conftest.py:

import os
if not any(os.environ.get(n) for n in ('LOGNAME','USER','LNAME','USERNAME')): os.environ['USERNAME'] = 'tester'

Or inject in tox.ini: [testenv] setenv = USERNAME = tester

Impact:
Any Windows/CI environment invoking pytest under Python 3.13+ without a username env var will fail until patched. Silent in earlier versions because getpass.getuser() returned a fallback or raised only ImportError/KeyError.
Regression Risk: Low. Adding OSError aligns with documented new behavior. Does not affect normal environments where env vars are present.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions