{"record":{"id":"34d5d07d60954ceb","repo":"mem0ai/mem0","slug":"cannot-reset-a-closed-sqlitemanager","errorCode":null,"errorMessage":"Cannot reset a closed SQLiteManager","messagePattern":"Cannot reset a closed SQLiteManager","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"mem0/memory/storage.py","lineNumber":329,"sourceCode":"            \"\"\",\n                (session_scope, limit),\n            )\n            rows = cur.fetchall()\n\n        return [\n            {\n                \"role\": r[0],\n                \"content\": r[1],\n                \"name\": r[2],\n                \"created_at\": r[3],\n            }\n            for r in rows\n        ]\n\n    def reset(self) -> None:\n        \"\"\"Drop both tables. Caller is expected to replace this instance.\"\"\"\n        if not self.connection:\n            raise RuntimeError(\"Cannot reset a closed SQLiteManager\")\n        with self._lock:\n            try:\n                self.connection.execute(\"BEGIN\")\n                self.connection.execute(\"DROP TABLE IF EXISTS history\")\n                self.connection.execute(\"DROP TABLE IF EXISTS messages\")\n                self.connection.execute(\"COMMIT\")\n            except Exception as e:\n                self.connection.execute(\"ROLLBACK\")\n                logger.error(f\"Failed to reset tables: {e}\")\n                raise\n\n    def close(self) -> None:\n        if self.connection:\n            self.connection.close()\n            self.connection = None\n\n    def __del__(self):\n        self.close()","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0/memory/storage.py#L311-L347","documentation":"SQLiteManager.reset() raises RuntimeError when self.connection is falsy — the manager was closed via close() (or never fully opened) and its SQLite handle is gone. reset() drops the history and messages tables inside a transaction; without a live connection there is nothing to drop, so it refuses rather than crash with an opaque sqlite error. The docstring states the contract: the caller is expected to replace this instance after use.","triggerScenarios":"Calling manager.reset() after manager.close(); resetting inside Memory.reset() when the underlying SQLiteManager was already closed (e.g. memory.close() then memory.reset()); holding a stale manager reference across an application shutdown/restart cycle.","commonSituations":"Test teardown code that closes the storage then a fixture-level reset runs afterwards; long-lived services that close() on shutdown but have a background task that later triggers reset; calling reset() twice where the first path closed the connection.","solutions":["Create a fresh SQLiteManager (or a fresh Memory) and reset that, since reset() is terminal anyway — the instance must be replaced","Ensure reset() runs before close() in shutdown/teardown ordering","Guard calls: if manager.connection is None, skip reset or reopen the manager first"],"exampleFix":"# before\nmanager.close()\nmanager.reset()  # RuntimeError\n\n# after\nmanager.reset()   # reset first\nmanager.close()    # then close; or simply discard the manager and build a new one","handlingStrategy":"validation","validationCode":"if getattr(manager, \"connection\", None) is None:\n    manager = SQLiteManager(...)  # rebuild instead of resetting a closed one","typeGuard":null,"tryCatchPattern":"try:\n    manager.reset()\nexcept RuntimeError:\n    pass  # already closed; nothing to reset","preventionTips":["Order teardown: reset() then close(), never the reverse","Treat a closed manager as single-use: build a new instance","Centralize lifecycle transitions in one shutdown routine"],"tags":["sqlite","storage","lifecycle","reset","runtime-error"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}