{"record":{"id":"e440ec4c86288baa","repo":"pytest-dev/pytest","slug":"self-is-the-lower-most-scope","errorCode":null,"errorMessage":"{self} is the lower-most scope","messagePattern":"(.+?) is the lower-most scope","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/scope.py","lineNumber":46,"sourceCode":"              ->>> higher ->>>\n\n    Function < Class < Module < Package < Session\n\n              <<<- lower  <<<-\n    \"\"\"\n\n    # Scopes need to be listed from lower to higher.\n    Function = \"function\"\n    Class = \"class\"\n    Module = \"module\"\n    Package = \"package\"\n    Session = \"session\"\n\n    def next_lower(self) -> Scope:\n        \"\"\"Return the next lower scope.\"\"\"\n        index = _SCOPE_INDICES[self]\n        if index == 0:\n            raise ValueError(f\"{self} is the lower-most scope\")\n        return _ALL_SCOPES[index - 1]\n\n    def next_higher(self) -> Scope:\n        \"\"\"Return the next higher scope.\"\"\"\n        index = _SCOPE_INDICES[self]\n        if index == len(_SCOPE_INDICES) - 1:\n            raise ValueError(f\"{self} is the upper-most scope\")\n        return _ALL_SCOPES[index + 1]\n\n    def __lt__(self, other: Scope) -> bool:\n        self_index = _SCOPE_INDICES[self]\n        other_index = _SCOPE_INDICES[other]\n        return self_index < other_index\n\n    @classmethod\n    def from_user(\n        cls, scope_name: ScopeName, descr: str, where: str | None = None\n    ) -> Scope:","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/scope.py#L28-L64","documentation":"pytest models fixture lifetimes as an ordered Scope enum: Function < Class < Module < Package < Session. Scope.next_lower() walks one step down that chain. Function is at index 0, so it has no lower neighbor and the call refuses rather than return a sentinel. The error is raised from internal scope-walking code, not from user-facing config parsing, so it signals a programming bug in pytest internals or a plugin that walks scopes without a bounds check.","triggerScenarios":"Calling Scope.Function.next_lower() directly, or any helper that iterates _ALL_SCOPES downward starting from Function. Reachable only via code that holds a Scope enum member and asks for the next-lower one; not produced by ini config or CLI flags.","commonSituations":"Plugin authors implementing fixture finalization that walks scopes; porting an old pytest fork whose scope list differed; an internal refactor that drops the bounds check before calling next_lower(). End users running stock pytest effectively never see this.","solutions":["Guard the call: check `scope is not Scope.Function` (or `scope != _ALL_SCOPES[0]`) before invoking next_lower().","Iterate the module-level HIGH_SCOPES list (all scopes except Function) instead of walking next_lower() from the bottom.","If you genuinely need a sentinel below Function, model it as a separate value rather than relying on next_lower() to produce one."],"exampleFix":"# before\nlower = scope.next_lower()\n\n# after\nif scope is Scope.Function:\n    lower = None\nelse:\n    lower = scope.next_lower()","handlingStrategy":"validation","validationCode":"from _pytest.scope import Scope, _ALL_SCOPES\n\ndef safe_next_lower(scope: Scope):\n    # Validate before calling next_lower() to avoid ValueError on Function.\n    if scope is _ALL_SCOPES[0]:\n        return None\n    return scope.next_lower()","typeGuard":"from _pytest.scope import Scope, _ALL_SCOPES\n\ndef has_lower_scope(scope: Scope) -> bool:\n    \"\"\"True when next_lower() is safe to call.\"\"\"\n    return scope is not _ALL_SCOPES[0]","tryCatchPattern":"try:\n    lower = scope.next_lower()\nexcept ValueError:\n    # scope is Function; nothing below it\n    lower = None","preventionTips":["Treat next_lower() as partial: always check against the lowest scope first.","Prefer iterating the module-level _ALL_SCOPES/HIGH_SCOPES lists over walking next_lower().","In plugin code, never assume a caller-provided scope has a lower neighbor."],"tags":["scope","fixtures","internal","enum"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}