Skip to content

PermissionError raised on Windows during logfile deletion for retention policies propagates unhandled during exit #1495

Description

@not-sekiun

On program exit, loguru attempts to delete log files following a retention policy. However, on Windows, when some of those log files still have open file handles on them, a PermissionError is raised and propagates unhandled causing an exception stack trace to bubble up, this also has the side effect of preventing other log files that have no open file handles on them (and thus could have been deleted during the retention policy sweep) from being deleted. I noticed this bug specifically when running a program that only retains 1 logfile in a centralized log directory. Sometimes I run multiple instances of this program that all log to the same directory hence the open file handle problem. Ideally each client when exiting just attempts to delete whatever it can rather than letting the exception bubble up and interrupt the retention deletion process

Here is a PoC, tested on Windows 11 with Python 3.14

import time

from loguru import logger


from loguru import logger

# Instance 1 starts up and keeps running, holding its log file open.
instance_1 = logger.add("app_{time}.log", retention=1)
logger.info("Instance 1 is running")

time.sleep(1)  # Give the two instances distinct timestamps.

# Instance 2 starts up later, then exits almost immediately.
instance_2 = logger.add("app_{time}.log", retention=1)

# Instance 2 exits. Retention keeps the newest file (instance 2's own, now
# closed) and deletes the older one but instance 1 still has that one open.
logger.remove(instance_2)  # PermissionError: [WinError 32]

This is the output on my machine

$ uv run python -c "import loguru; print(loguru.__version__)"
0.7.3

$ cat .\test.py
import time

from loguru import logger


from loguru import logger

# Instance 1 starts up and keeps running, holding its log file open.
instance_1 = logger.add("app_{time}.log", retention=1)
logger.info("Instance 1 is running")

time.sleep(1)  # Give the two instances distinct timestamps.

# Instance 2 starts up later, then exits almost immediately.
instance_2 = logger.add("app_{time}.log", retention=1)

# Instance 2 exits. Retention keeps the newest file (instance 2's own, now
# closed) and deletes the older one but instance 1 still has that one open.
logger.remove(instance_2)  # PermissionError: [WinError 32]

$ uv run python .\test.py
2026-07-31 00:09:57.573 | INFO     | __main__:<module>:10 - Instance 1 is running
Traceback (most recent call last):
  File "C:\Users\sekiun\loguru_test\test.py", line 19, in <module>
    logger.remove(instance_2)  # PermissionError: [WinError 32]
    ~~~~~~~~~~~~~^^^^^^^^^^^^
  File "C:\Users\sekiun\loguru_test\.venv\Lib\site-packages\loguru\_logger.py", line 1066, in remove
    handler.stop()
    ~~~~~~~~~~~~^^
  File "C:\Users\sekiun\loguru_test\.venv\Lib\site-packages\loguru\_handler.py", line 223, in stop
    self._sink.stop()
    ~~~~~~~~~~~~~~~^^
  File "C:\Users\sekiun\loguru_test\.venv\Lib\site-packages\loguru\_file_sink.py", line 212, in stop
    self._terminate_file(is_rotating=False)
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "C:\Users\sekiun\loguru_test\.venv\Lib\site-packages\loguru\_file_sink.py", line 290, in _terminate_file
    self._retention_function(list(logs))
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "C:\Users\sekiun\loguru_test\.venv\Lib\site-packages\loguru\_file_sink.py", line 77, in retention_count
    os.remove(log)
    ~~~~~~~~~^^^^^
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'app_2026-07-31_00-09-57_573000.log'

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions