mem0ai/mem0 · error · RuntimeError

Cannot reset a closed SQLiteManager

Error message

Cannot reset a closed SQLiteManager

What it means

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.

Source

Thrown at mem0/memory/storage.py:329

            """,
                (session_scope, limit),
            )
            rows = cur.fetchall()

        return [
            {
                "role": r[0],
                "content": r[1],
                "name": r[2],
                "created_at": r[3],
            }
            for r in rows
        ]

    def reset(self) -> None:
        """Drop both tables. Caller is expected to replace this instance."""
        if not self.connection:
            raise RuntimeError("Cannot reset a closed SQLiteManager")
        with self._lock:
            try:
                self.connection.execute("BEGIN")
                self.connection.execute("DROP TABLE IF EXISTS history")
                self.connection.execute("DROP TABLE IF EXISTS messages")
                self.connection.execute("COMMIT")
            except Exception as e:
                self.connection.execute("ROLLBACK")
                logger.error(f"Failed to reset tables: {e}")
                raise

    def close(self) -> None:
        if self.connection:
            self.connection.close()
            self.connection = None

    def __del__(self):
        self.close()

View on GitHub (pinned to 001c235229)

Solutions

  1. Create a fresh SQLiteManager (or a fresh Memory) and reset that, since reset() is terminal anyway — the instance must be replaced
  2. Ensure reset() runs before close() in shutdown/teardown ordering
  3. Guard calls: if manager.connection is None, skip reset or reopen the manager first

Example fix

# before
manager.close()
manager.reset()  # RuntimeError

# after
manager.reset()   # reset first
manager.close()    # then close; or simply discard the manager and build a new one
Defensive patterns

Strategy: validation

Validate before calling

if getattr(manager, "connection", None) is None:
    manager = SQLiteManager(...)  # rebuild instead of resetting a closed one

Try / catch

try:
    manager.reset()
except RuntimeError:
    pass  # already closed; nothing to reset

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15). Data as JSON: /api/errors/34d5d07d60954ceb. Report an issue: GitHub.