Fix noisy 'I/O operation on closed file' during test teardown#21096
Merged
Fix noisy 'I/O operation on closed file' during test teardown#21096
Conversation
The prefect._internal logger's debug handler used a plain logging.StreamHandler. When background threads from the concurrency layer logged after pytest closed stderr, the stdlib's handleError() printed noisy tracebacks. SafeStreamHandler suppresses ValueError for closed streams while preserving all other error handling. Closes #16626 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Member
|
Could we solve this issue with a |
Collaborator
Author
@desertaxle i think we could write a fixture that'd resolve it for our CI, but gauging the reactions and report that prompted me coming back to this, that wouldn't help anyone else, so we'd have to document a workaround fixture that everyone would have to adopt. since i'm only changing the |
desertaxle
approved these changes
Mar 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #16626
Summary
_SafeStreamHandlertosrc/prefect/logging/handlers.py— suppressesValueErrorfrom closed streams inhandleError()debughandler inlogging.yml(only servesprefect._internal, no user-facing loggers affected)This is a stdlib
logging.StreamHandler+ daemon thread race condition. When daemon threads from Prefect's concurrency layer log after pytest closes stderr, the stdlib'shandleError()prints noisy--- Logging error ---tracebacks._SafeStreamHandlersilences that specific case.Why a subclass?
The stdlib
StreamHandler.emit()catchesValueErrorinternally and routes it tohandleError(), which prints the traceback. There's no configuration point to suppress this — subclassing is the only clean approach.The subclass is scoped to the single
debughandler used byprefect._internal. User-facing loggers (prefect,prefect.flow_runs,prefect.task_runs, etc.) usePrefectConsoleHandlerorAPILogHandlerand are completely unaffected. It's underscore-prefixed to signal it's an internal implementation detail.Root cause: stdlib reproduction (zero Prefect imports)
Why not graceful thread shutdown instead?
The concurrency layer's threads (global event loop, run-sync loop, service workers) are daemon threads by design — they're meant to die with the process without blocking exit. The race window is between pytest closing stderr and the interpreter killing daemon threads. We don't control that ordering.
The daemon threads are shutting down; they just sometimes get one last log call in after the stream is gone.
_SafeStreamHandlerhandles that inherent timing gap.🤖 Generated with Claude Code