diff --git a/gui/log_viewer.py b/gui/log_viewer.py
index 62f31a7..e4b9dc8 100644
--- a/gui/log_viewer.py
+++ b/gui/log_viewer.py
@@ -306,6 +306,13 @@ class LogViewer(QWidget):
self.error_display.append(html_msg)
self._error_count += 1
self._tab_widget.setTabText(1, f"Errors ({self._error_count})")
+ elif '\u274c' in message:
+ # Worker-level error (❌ prefix) — show in both All and Errors tabs.
+ html_msg = f'{escaped}'
+ self.log_display.append(html_msg)
+ self.error_display.append(html_msg)
+ self._error_count += 1
+ self._tab_widget.setTabText(1, f"Errors ({self._error_count})")
else:
# Explicitly wrap in a white span so Qt doesn't inherit red from
# a preceding [MISMATCH] HTML append.
diff --git a/gui/translation_tab.py b/gui/translation_tab.py
index 61d137d..4c08eec 100644
--- a/gui/translation_tab.py
+++ b/gui/translation_tab.py
@@ -1761,6 +1761,14 @@ class TranslationTab(QWidget):
if isinstance(message, str) and message.startswith("MISMATCH_EVENT:"):
self.on_mismatch_detected()
return # marker is internal, not displayed
+ # Forward error messages to the log viewer directly. These worker-level
+ # errors are not written to the log file so the tail won't capture them.
+ if isinstance(message, str) and '\u274c' in message:
+ try:
+ if hasattr(self, 'translation_log_viewer') and self.translation_log_viewer:
+ self.translation_log_viewer.append_log_message(message)
+ except Exception:
+ pass
try:
pattern = r'^\W*(?P[^:]+):.*?\[Input:\s*(?P\d+)\].*?\[Output:\s*(?P