{"record":{"id":"92d0f631513887c8","repo":"D4Vinci/Scrapling","slug":"session-session-id-not-found","errorCode":null,"errorMessage":"Session '{session_id}' not found","messagePattern":"Session '(.+?)' not found","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"scrapling/spiders/session.py","lineNumber":56,"sourceCode":"        if lazy:\n            self._lazy_sessions.add(session_id)\n\n        return self\n\n    def remove(self, session_id: str) -> None:\n        \"\"\"Removes a session.\n\n        :param session_id: ID of session to remove\n        \"\"\"\n        _ = self.pop(session_id)\n\n    def pop(self, session_id: str) -> Session:\n        \"\"\"Remove and returns a session.\n\n        :param session_id: ID of session to remove\n        \"\"\"\n        if session_id not in self._sessions:\n            raise KeyError(f\"Session '{session_id}' not found\")\n\n        session = self._sessions.pop(session_id)\n        if session_id in self._lazy_sessions:\n            self._lazy_sessions.remove(session_id)\n\n        if session and self._default_session_id == session_id:\n            self._default_session_id = next(iter(self._sessions), None)\n\n        return session\n\n    @property\n    def default_session_id(self) -> str:\n        if self._default_session_id is None:\n            raise RuntimeError(\"No sessions registered\")\n        return self._default_session_id\n\n    @property\n    def session_ids(self) -> list[str]:","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/D4Vinci/Scrapling/blob/5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f/scrapling/spiders/session.py#L38-L74","documentation":"SessionManager.pop()/remove() raise KeyError when asked for a session_id that is not registered. The manager keeps sessions in a dict keyed by id; removing an unknown id means it was never added, was already removed, or the id is misspelled.","triggerScenarios":"manager.remove('http') when only 'browser' was registered; double-cleanup code that removes the same session in teardown and again in an outer finally block.","commonSituations":"Teardown routines running twice (finally + atexit); typos in session ids; removing a session that a failed setup step never actually registered.","solutions":["Guard removals: if session_id in manager.session_ids: manager.remove(session_id).","Use session_ids (or a try/except KeyError) to make teardown idempotent.","Centralize session-id constants in one place instead of repeating string literals."],"exampleFix":"# before\nmanager.remove('htp')  # KeyError (typo)\n\n# after\nif 'http' in manager.session_ids:\n    manager.remove('http')","handlingStrategy":"validation","validationCode":"def safe_remove(manager, session_id: str) -> bool:\n    if session_id in manager.session_ids:\n        manager.remove(session_id)\n        return True\n    return False","typeGuard":null,"tryCatchPattern":"from contextlib import suppress\n\nwith suppress(KeyError):\n    manager.remove(session_id)  # idempotent teardown","preventionTips":["Make teardown idempotent — guard removes with session_ids membership or suppress KeyError.","Centralize session-id literals to avoid typo-driven misses."],"tags":["session","key-error","teardown","validation"],"backgroundTag":null,"analyzedSha":"5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f","analyzedAt":"2026-08-14T22:23:09.440Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}