#9214: Fix: EPIPE exception in systemd service operations
gateway
stale
Cluster:
Error Handling and Memory Management
Fixes #9205
## Problem
During rapid config-triggered restarts via SIGUSR1, uncaught EPIPE exceptions were thrown from systemd daemon operations when stdout writes attempted to write to closed pipes.
## Root Cause
Multiple `stdout.write()` calls throughout `src/daemon/systemd.ts` didn't check if the stream was still writable before writing. When rapid restarts occurred (~3 seconds apart), the process holding the stdout pipe would terminate before the write completed, causing crashes.
## Solution
Added `safeWriteToStdout()` helper function that:
- Checks `stream.writable` before attempting to write
- Wraps write in try-catch to gracefully handle EPIPE and other write errors
- Silently ignores errors since the operation (restart/stop/install) has already succeeded
## Changes
Updated all stdout writes in:
- `installSystemdService()` - 2 writes
- `uninstallSystemdService()` - 2 writes
- `stopSystemdService()` - 1 write
- `restartSystemdService()` - 1 write (original bug location)
- `uninstallLegacySystemdUnits()` - 3 writes
## Impact
✅ Prevents uncaught EPIPE crashes during rapid systemd service restarts
✅ No functional changes - operations still succeed, just safer logging
✅ Minimal, defensive code change
✅ Comprehensive fix for all stdout writes in daemon operations
## Testing
- Lint passes
- Build succeeds
- Fix follows suggested approach from bug report
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
Updates `src/daemon/systemd.ts` to route all user-facing `stdout.write()` logging through a new `safeWriteToStdout()` helper, intended to avoid EPIPE crashes during rapid config-triggered restarts (SIGUSR1) when the stdout pipe consumer disconnects.
The change is localized to systemd service install/un mostinstall/stop/restart and legacy unit uninstall flows, and aims to make status logging resilient without altering systemctl/file operation behavior.
<h3>Confidence Score: 3/5</h3>
- This PR is reasonably safe but may not fully fix the reported crash condition.
- The change is small and localized, but the core mitigation relies on catching synchronous exceptions from `stream.write()`, while EPIPE on a closed pipe is typically emitted asynchronously; if that’s the failure mode in #9205, the crash can still occur.
- src/daemon/systemd.ts
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#6273: fix: handle EPIPE errors gracefully in daemon operations
by batumilove · 2026-02-01
85.3%
#22108: fix: prevent local DoS by fully clearing systemd services on uninstall
by berkeserce · 2026-02-20
74.8%
#16016: fix: update systemd unit version on gateway restart
by jbold · 2026-02-14
74.6%
#6577: fix: add null checks for stdout/stderr when using inherit-stdio fal...
by ncmalan · 2026-02-01
73.7%
#12308: fix(cli): redirect log output to stderr during completion script ge...
by mcaxtr · 2026-02-09
73.3%
#16185: fix: patch systemd unit version before service restart
by nozh · 2026-02-14
70.9%
#9036: fix: add systemd restart limits to prevent infinite crash-loops
by joetomasone · 2026-02-04
70.7%
#13084: fix(daemon): multi-layer defense against zombie gateway processes
by openperf · 2026-02-10
70.6%
#15345: fix(daemon): doctor --fix pollutes service PATH with dirs that don'...
by yinghaosang · 2026-02-13
70.3%
#21212: fix: detect and manage systemd system services (rebased)
by growthringsadvisory · 2026-02-19
69.7%