From 5ea9410914a235dd1d97909a244b031460671da3 Mon Sep 17 00:00:00 2001 From: Any Name Date: Sat, 18 Apr 2026 19:26:37 -0700 Subject: [PATCH] Wrap stdout/stderr.flush() in sync_write with try/except OSError The flush() method on lines 366-379 already catches OSError and ValueError when calling original_stdout.flush() / original_stderr.flush(), but the sync_write() method on line 361 and the tqdm branch in write() on line 336 do NOT. On Windows, when ComfyUI is launched as a child process with piped stdio, certain conditions can leave the underlying handle in a state where flush() raises OSError [Errno 22] Invalid argument. Once that happens, the unhandled OSError propagates back through: print() in any custom node -> write(message) in this logger wrapper -> sync_write(message) -> original_*.flush() -> OSError [Errno 22] This kills prompt execution for any custom node that prints during INPUT_TYPES() or __init__ -- even on a benign log line like 'Dependencies already installed from previous run' in LatentSyncWrapper. Symptoms users will recognize: - LatentSync, Sonic, Hallo 2 all failing with [Errno 22] before reading inputs - 'Logging error' lines spammed throughout the console - The error in the user's traceback always points back to prestartup_script.py:361 / app/logger.py:35 super().flush() Wrapping the flush calls in try/except (OSError, ValueError) -- the exact same pattern already used in self.flush() on line 378 -- breaks the cascade. Print failures degrade silently to file-only logging instead of taking down prompt execution. --- prestartup_script.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/prestartup_script.py b/prestartup_script.py index dabd39da..63428af8 100644 --- a/prestartup_script.py +++ b/prestartup_script.py @@ -332,8 +332,14 @@ try: if '100%' in message: self.sync_write(message) else: - write_stderr(message) - original_stderr.flush() + # Wrap flush() to match the safer behaviour of + # self.flush() below — a broken pipe must not + # kill the calling print() (and thus the node). + try: + write_stderr(message) + original_stderr.flush() + except (OSError, ValueError): + pass else: self.sync_write(message) else: @@ -356,12 +362,20 @@ try: if not file_only: with std_log_lock: - if self.is_stdout: - write_stdout(message) - original_stdout.flush() - else: - write_stderr(message) - original_stderr.flush() + # Wrap flush() in try/except to match self.flush() + # below. Without this, an OSError from a broken + # stdio pipe (e.g. Windows [Errno 22] Invalid argument) + # propagates up through every print() call in every + # custom node, killing prompt execution. + try: + if self.is_stdout: + write_stdout(message) + original_stdout.flush() + else: + write_stderr(message) + original_stderr.flush() + except (OSError, ValueError): + pass def flush(self): try: