From 1a256b86702bb2c28b7e2111163e787540b3f19c Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 7 Mar 2026 16:40:38 -0800 Subject: [PATCH] Daemon: tighten systemctl failure classification --- src/daemon/systemd.test.ts | 17 +++++++++++++++++ src/daemon/systemd.ts | 9 ++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/daemon/systemd.test.ts b/src/daemon/systemd.test.ts index 984f0111b0c..7271823007c 100644 --- a/src/daemon/systemd.test.ts +++ b/src/daemon/systemd.test.ts @@ -224,6 +224,23 @@ describe("isSystemdServiceEnabled", () => { expect(result).toBe(false); }); + it("throws when generic wrapper errors report infrastructure failures", async () => { + const { isSystemdServiceEnabled } = await import("./systemd.js"); + mockManagedUnitPresent(); + execFileMock.mockImplementationOnce((_cmd, args, _opts, cb) => { + expect(args).toEqual(["--user", "is-enabled", "openclaw-gateway.service"]); + const err = new Error( + "Command failed: systemctl --user is-enabled openclaw-gateway.service", + ) as Error & { code?: number }; + err.code = 1; + cb(err, "", "read-only file system"); + }); + + await expect( + isSystemdServiceEnabled({ env: { HOME: "/tmp/openclaw-test-home" } }), + ).rejects.toThrow("systemctl is-enabled unavailable: read-only file system"); + }); + it("throws when systemctl is-enabled fails for non-state errors", async () => { const { isSystemdServiceEnabled } = await import("./systemd.js"); mockManagedUnitPresent(); diff --git a/src/daemon/systemd.ts b/src/daemon/systemd.ts index 20d3508f611..463e6a49f4b 100644 --- a/src/daemon/systemd.ts +++ b/src/daemon/systemd.ts @@ -189,8 +189,7 @@ function isSystemctlBusUnavailable(detail: string): boolean { normalized.includes("failed to connect to user scope bus") || normalized.includes("dbus_session_bus_address") || normalized.includes("xdg_runtime_dir") || - normalized.includes("no medium found") || - normalized.includes("connection refused") + normalized.includes("no medium found") ); } @@ -203,7 +202,11 @@ function isGenericSystemctlIsEnabledFailure(detail: string): boolean { normalized.startsWith("command failed: systemctl") && normalized.includes(" is-enabled ") && !normalized.includes("permission denied") && - !normalized.includes("access denied") + !normalized.includes("access denied") && + !normalized.includes("no space left") && + !normalized.includes("read-only file system") && + !normalized.includes("out of memory") && + !normalized.includes("cannot allocate memory") ); }