Skip to content

Shutdown-time logging error: SQLiteMemory.dispose_engine() logs after handler stream closed (ValueError: I/O operation on closed file) #1520

@AlbMej

Description

@AlbMej

Triggered during a Pytest run for me

Describe the bug

PyRIT’s SQLite memory cleanup can emit a shutdown-time logging error when dispose_engine() logs after a logging handler’s underlying stream has already been closed. This results in:

ValueError: I/O operation on closed file

The cleanup is registered via atexit.register(self.dispose_engine) and weakref.finalize(self, self.dispose_engine) in MemoryInterface.cleanup(). During interpreter shutdown these callbacks can run after other code has already closed logging streams/handlers.

Steps/Code to Reproduce

Steps:

mkdir pyrit-shutdown-log-repro
cd pyrit-shutdown-log-repro
uv venv --python 3.12
source .venv/bin/activate
uv pip install pyrit
uv run python repro_closed_logging_stream.py

Code (repro_closed_logging_stream.py):

import io
import logging

from pyrit.memory.sqlite_memory import SQLiteMemory

# Simulate an application/test-runner that creates a handler writing to a stream,
# then closes that stream before interpreter shutdown.
stream = io.StringIO()
handler = logging.StreamHandler(stream)

root = logging.getLogger()
root.addHandler(handler)
root.setLevel(logging.INFO)

# Instantiating SQLiteMemory registers shutdown cleanup via atexit + weakref.finalize.
SQLiteMemory()

# Close the stream before interpreter shutdown; PyRIT's finalizer logs during shutdown.
stream.close()

print("created; stream closed; exiting now")

Expected Results

No shutdown-time logging error. Cleanup should be silent or robust even if log handler streams are already closed.

Actual Results

On process exit (after the script prints created; stream closed; exiting now), Python emits a logging error similar to:

ValueError: I/O operation on closed file
Call stack:
  File ".../site-packages/pyrit/memory/sqlite_memory.py", line 343, in dispose_engine
    logger.info("Engine disposed and all connections closed.")
Message: 'Engine disposed and all connections closed.'
Arguments: ()

Screenshots

N/A

Versions

  • OS: Linux (WSL2)
  • Python version: 3.12.x
  • PyRIT version: 0.11.0
  • pyrit.show_versions()
import pyrit
pyrit.show_versions()

Output:

pyrit.show_versions()

System:
    python: 3.12.3 (main, Mar  3 2026, 12:15:18) [GCC 13.3.0]
executable: /reponame/.venv/bin/python
   machine: Linux-6.6.87.2-microsoft-standard-WSL2-x86_64-with-glibc2.39

Python dependencies:
        pyrit: 0.11.0
       Cython: None
        numpy: 2.2.6
       openai: 2.21.0
    packaging: 26.0
          pip: None
        scipy: 1.17.0
   setuptools: 79.0.1
      sqlite3: None
        torch: 2.8.0
 transformers: 5.2.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions