{"record":{"id":"46c3886d40c2f0bb","repo":"pytest-dev/pytest","slug":"self-is-the-upper-most-scope","errorCode":null,"errorMessage":"{self} is the upper-most scope","messagePattern":"(.+?) is the upper-most scope","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/scope.py","lineNumber":53,"sourceCode":"    # 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:\n        \"\"\"\n        Given a scope name from the user, return the equivalent Scope enum. Should be used\n        whenever we want to convert a user provided scope name to its enum object.\n\n        If the scope name is invalid, construct a user friendly message and call pytest.fail.\n        \"\"\"\n        from _pytest.outcomes import fail","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/scope.py#L35-L71","documentation":"Mirror of the lower-most check: Scope.next_higher() walks one step up the Function < Class < Module < Package < Session chain. Session is the highest member (last index), so next_higher() on it has no target and raises ValueError. Like its sibling, this guards internal scope-walking logic and indicates a programming error, not a user configuration problem.","triggerScenarios":"Calling Scope.Session.next_higher(), or any loop/helper that walks _ALL_SCOPES upward from Session without a bound. Produced by code paths in fixtures or plugins that ask for the next-higher scope, never by ini/CLI input.","commonSituations":"Plugin code that computes the enclosing scope of a session-scoped fixture; a refactor that walks scopes upward without checking for the top; tests that exercise Scope directly.","solutions":["Guard the call: check `scope is not Scope.Session` before invoking next_higher().","Use `index < len(_SCOPE_INDICES) - 1` as the bound, mirroring the source check at scope.py:52.","Prefer iterating _ALL_SCOPES explicitly with a bounded loop rather than relying on next_higher() to stop."],"exampleFix":"# before\nhigher = scope.next_higher()\n\n# after\nif scope is Scope.Session:\n    higher = None\nelse:\n    higher = scope.next_higher()","handlingStrategy":"validation","validationCode":"from _pytest.scope import Scope, _ALL_SCOPES, _SCOPE_INDICES\n\ndef safe_next_higher(scope: Scope):\n    if scope is _ALL_SCOPES[-1]:\n        return None\n    return scope.next_higher()","typeGuard":"from _pytest.scope import Scope, _ALL_SCOPES\n\ndef has_higher_scope(scope: Scope) -> bool:\n    \"\"\"True when next_higher() is safe to call.\"\"\"\n    return scope is not _ALL_SCOPES[-1]","tryCatchPattern":"try:\n    higher = scope.next_higher()\nexcept ValueError:\n    # scope is Session; nothing above it\n    higher = None","preventionTips":["Treat next_higher() as partial: check against Session (the last scope) first.","Use the index-based bound `index < len(_SCOPE_INDICES) - 1` exactly as the source does.","Document scope-walking helpers as partial functions so callers know to handle None."],"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"}