@@ -245,6 +245,28 @@ def _process_message(self, message):
245245 self .in_traceback = False
246246 self .buffer = []
247247 else :
248+ # ═══════════════════════════════════════════════════════════════
249+ # CRITICAL FIX (2026-01-06): Check completion marker BEFORE buffer.append()
250+ # ═══════════════════════════════════════════════════════════════
251+ # BUG: "Prompt executed in X seconds" was being added to buffer BEFORE
252+ # is_complete_traceback() detected completion, causing it to be
253+ # recorded as part of the error message.
254+ #
255+ # SOLUTION: Intercept "Prompt executed" BEFORE appending to buffer.
256+ # Use current buffer (without this line) for recording.
257+ #
258+ # DO NOT MOVE THIS CHECK AFTER buffer.append()!
259+ # ═══════════════════════════════════════════════════════════════
260+ if "Prompt executed" in message :
261+ full_traceback = "" .join (self .buffer )
262+ if full_traceback .strip (): # Only record if buffer has content
263+ result = ErrorAnalyzer .analyze (full_traceback )
264+ suggestion , metadata = result if result else (None , None )
265+ self ._record_analysis (full_traceback , suggestion , metadata )
266+ self .in_traceback = False
267+ self .buffer = []
268+ return
269+
248270 self .buffer .append (message )
249271 self .last_buffer_time = current_time
250272 full_traceback = "" .join (self .buffer )
@@ -295,6 +317,60 @@ def _record_analysis(self, full_traceback, suggestion, metadata=None):
295317 suggestion: Suggestion text (or None if no match)
296318 metadata: Optional metadata dict with pattern info (from F4)
297319 """
320+ # DEBUG: Log what's being recorded
321+ logging .info (f"[Doctor] _record_analysis called with traceback preview: { full_traceback [:100 ] if full_traceback else 'None' } ..." )
322+
323+ # ═══════════════════════════════════════════════════════════════
324+ # CRITICAL FIX (2026-01-06): Prevent non-error messages from
325+ # overwriting legitimate error records
326+ # ═══════════════════════════════════════════════════════════════
327+ # BUG: Normal messages like "Prompt executed in X seconds" were
328+ # being recorded as errors, overwriting real error logs.
329+ #
330+ # SOLUTION: Validate that full_traceback contains actual error
331+ # indicators before recording.
332+ #
333+ # DO NOT REMOVE THIS VALIDATION!
334+ # ═══════════════════════════════════════════════════════════════
335+
336+ # Skip recording if no actual error content
337+ # This prevents normal messages like "Prompt executed in X seconds" from
338+ # overwriting legitimate error records
339+ if not full_traceback :
340+ return
341+
342+ # Explicit exclusion for normal execution messages
343+ # These messages should NEVER be recorded as errors
344+ normal_messages = [
345+ "Prompt executed in" ,
346+ "got prompt" ,
347+ "Executing node" ,
348+ "To see the GUI go to:" ,
349+ "Starting server" ,
350+ ]
351+ for normal_msg in normal_messages :
352+ if normal_msg in full_traceback and "Error" not in full_traceback and "Exception" not in full_traceback :
353+ logging .debug (f"[Doctor] Skipping normal message: { full_traceback [:100 ]} " )
354+ return
355+
356+ # Require at least one error indicator
357+ error_indicators = [
358+ "Traceback (most recent call last):" ,
359+ "Error:" ,
360+ "Error " , # Catch RuntimeError, ValueError etc without colon
361+ "Exception:" ,
362+ "Exception " ,
363+ "Failed to validate" ,
364+ "❌ CRITICAL" ,
365+ "⚠️ Meta Tensor" ,
366+ ]
367+ has_error_indicator = any (indicator in full_traceback for indicator in error_indicators )
368+
369+ # Also accept if we have a valid suggestion (pattern matched)
370+ if not has_error_indicator and not suggestion :
371+ logging .debug (f"[Doctor] Skipping non-error message (no indicators): { full_traceback [:100 ]} " )
372+ return
373+
298374 node_context = ErrorAnalyzer .extract_node_context (full_traceback )
299375 timestamp = datetime .datetime .now ().isoformat ()
300376
0 commit comments