Skip to content

fix(core): guard print() calls in run_conversation() against OSError#1668

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-923bc090
Mar 17, 2026
Merged

fix(core): guard print() calls in run_conversation() against OSError#1668
teknium1 merged 1 commit into
mainfrom
hermes/hermes-923bc090

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Reimplementation of the fix from PR #1358 by @mr-emmett-one (323 commits stale, had a variable deletion bug). Addresses issue #845.

Problem

In headless environments (systemd services, Docker, nohup), stdout can become unavailable mid-session. Raw print() raises OSError: [Errno 5] Input/output error. The critical failure cascade:

  1. print() in quiet_mode display raises OSError
  2. The except Exception handler catches it
  3. The error handler's own print(f"❌ {error_msg}") also raises OSError
  4. This propagates out of run_conversation() entirely
  5. Cron scheduler marks the job as error — completed work is never delivered

Fix

  • _safe_print() — new static method that wraps print() with try/except OSError. Silently drops output when stdout is broken.
  • _vprint() now uses _safe_print() — protects all calls through the verbose print path automatically.
  • Raw print() calls in run_conversation() hot path converted to _safe_print(): starting conversation, interrupt, budget exhausted, preflight compression, context cache, conversation completed.
  • Error handler (the cascading crash point) gets explicit try/except with logger.error() fallback so diagnostic messages aren't silently lost.

Fixes #845

In headless environments (systemd, Docker, nohup) stdout can become
unavailable mid-session. Raw print() raises OSError which crashes
cron jobs — agent finishes work but delivery never happens because
the error handler's own print() also raises OSError.

Fix:
- Add _safe_print() static method that wraps print() with try/except
  OSError — silently drops output when stdout is broken
- Make _vprint() use _safe_print() — protects all calls through the
  verbose print path
- Convert raw print() calls in run_conversation() hot path to use
  _safe_print(): starting conversation, interrupt, budget exhausted,
  preflight compression, context cache, conversation completed
- Error handler print (the cascading crash point) gets explicit
  try/except with logger.error() fallback so diagnostics aren't lost

Fixes #845
Closes #1358 (superseded — PR was 323 commits stale with a bug)
@teknium1 teknium1 merged commit a3ac142 into main Mar 17, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: guard print() calls in run_conversation() against OSError when stdout is unavailable (systemd/headless)

1 participant