pytest ScopeMismatch: function scoped fixture (tested)

ScopeMismatch: You tried to access the function scoped fixture X with a session scoped request object means a wider-scoped fixture depends on a narrower one. Widen the dependency's scope, narrow the consumer, or use tmp_path_factory / pytest.MonkeyPatch.context() for the built-ins.

A fixture can only use fixtures with the same or wider scope (function < class < module < package < session). A session fixture is created once, so it cannot depend on something that is recreated for every test. Measured on pytest 9.1.1.

1. A session fixture using your function-scoped fixture

$ cat test_a.py
import pytest

@pytest.fixture
def db_url():
    return "sqlite://"

@pytest.fixture(scope="session")
def engine(db_url):
    return {"url": db_url}

def test_x(engine):
    assert engine
$ pytest -q -p no:cacheprovider | grep -E "^ScopeMismatch|^ERROR"
ScopeMismatch: You tried to access the function scoped fixture db_url with a session scoped request object. Requesting fixture stack:
ERROR test_a.py::test_x - Failed: ScopeMismatch: You tried to access the func...

The error names the narrower fixture (db_url, function scope) and the scope that asked for it (session). The test is reported as ERROR at setup.

Fix: widen the dependency (or narrow the consumer)

$ cat test_b.py
import pytest

@pytest.fixture(scope="session")
def db_url():
    return "sqlite://"

@pytest.fixture(scope="session")
def engine(db_url):
    return {"url": db_url}

@pytest.fixture(scope="session")
def data_dir(tmp_path_factory):
    return tmp_path_factory.mktemp("data")

def test_x(engine, data_dir):
    assert engine and data_dir.exists()
$ pytest -q -p no:cacheprovider | tail -1
1 passed in 0.00s

Give db_url session scope too, or make engine function-scoped if it is cheap. For temporary directories in session fixtures use tmp_path_factory.mktemp(), the session-scoped counterpart of tmp_path, as data_dir does here.

2. Built-in fixtures: tmp_path and monkeypatch are function-scoped

$ cat test_c.py
import pytest

@pytest.fixture(scope="session")
def data_dir(tmp_path):
    return tmp_path

@pytest.fixture(scope="module")
def patched(monkeypatch):
    monkeypatch.setenv("X", "1")

def test_x(data_dir):
    pass

def test_y(patched):
    pass
$ pytest -q -p no:cacheprovider | grep -E "^ScopeMismatch"
ScopeMismatch: You tried to access the function scoped fixture tmp_path with a session scoped request object. Requesting fixture stack:
ScopeMismatch: You tried to access the function scoped fixture monkeypatch with a module scoped request object. Requesting fixture stack:

tmp_path, tmpdir, monkeypatch, capsys and caplog are function-scoped, so a module or session fixture cannot request them. For monkeypatch, use pytest.MonkeyPatch.context() inside the wider fixture; changes are undone when the fixture finishes (here, at the end of the module):

$ cat test_c.py
import os, pytest

@pytest.fixture(scope="module")
def patched():
    with pytest.MonkeyPatch.context() as mp:
        mp.setenv("X", "1")
        yield

def test_y(patched):
    assert os.environ["X"] == "1"
$ pytest -q -p no:cacheprovider | tail -1
1 passed in 0.00s

Related: pytest fixture not found, pytest ERROR at setup.

Frequently asked questions

What causes pytest ScopeMismatch?

A fixture with module or session scope requests a fixture with a narrower scope, usually function scope (the default).

How do I use tmp_path in a session fixture?

You cannot; use tmp_path_factory.mktemp('name'), which is session-scoped.

How do I use monkeypatch in a module-scoped fixture?

Use with pytest.MonkeyPatch.context() as mp: inside the fixture and yield; changes are undone when the fixture is torn down.

Written with AI assistance. Measured on 2026-10-23 with pytest 9.1.1 on Python 3.13.5 in a clean virtualenv. Each block was run verbatim and the output pasted unedited. PlainHeaders is our extension; Python and pytest are free.