From 296d5ede68783b06def4a08ddd048f1ba3ddbd33 Mon Sep 17 00:00:00 2001 From: Clawborn <261310391+Clawborn@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:27:20 +0800 Subject: [PATCH] Fix LaunchAgent missing TMPDIR and LANG environment variables Forward TMPDIR and LANG from the host environment into the generated LaunchAgent and systemd service environment. macOS launchd does not inherit shell environment variables, so TMPDIR is unset when the gateway runs as a LaunchAgent. This causes SQLite to fail with SQLITE_CANTOPEN because it cannot create journal/WAL temp files in the per-user temp directory (/var/folders/...). LANG is also forwarded to ensure consistent locale behavior for string collation and file I/O encoding. Fixes #20489 Co-authored-by: Clawborn --- src/daemon/service-env.test.ts | 33 +++++++++++++++++++++++++++++++++ src/daemon/service-env.ts | 4 ++++ 2 files changed, 37 insertions(+) diff --git a/src/daemon/service-env.test.ts b/src/daemon/service-env.test.ts index c9e86f7cf13..44d74009deb 100644 --- a/src/daemon/service-env.test.ts +++ b/src/daemon/service-env.test.ts @@ -282,6 +282,31 @@ describe("buildServiceEnvironment", () => { } }); + it("forwards TMPDIR from the host environment", () => { + const env = buildServiceEnvironment({ + env: { HOME: "/home/user", TMPDIR: "/var/folders/xw/abc123/T/" }, + port: 18789, + }); + expect(env.TMPDIR).toBe("/var/folders/xw/abc123/T/"); + }); + + it("forwards LANG from the host environment", () => { + const env = buildServiceEnvironment({ + env: { HOME: "/home/user", LANG: "en_US.UTF-8" }, + port: 18789, + }); + expect(env.LANG).toBe("en_US.UTF-8"); + }); + + it("omits TMPDIR and LANG when not set in host environment", () => { + const env = buildServiceEnvironment({ + env: { HOME: "/home/user" }, + port: 18789, + }); + expect(env.TMPDIR).toBeUndefined(); + expect(env.LANG).toBeUndefined(); + }); + it("uses profile-specific unit and label", () => { const env = buildServiceEnvironment({ env: { HOME: "/home/user", OPENCLAW_PROFILE: "work" }, @@ -301,6 +326,14 @@ describe("buildNodeServiceEnvironment", () => { }); expect(env.HOME).toBe("/home/user"); }); + + it("forwards TMPDIR and LANG for node services", () => { + const env = buildNodeServiceEnvironment({ + env: { HOME: "/home/user", TMPDIR: "/tmp/custom", LANG: "en_US.UTF-8" }, + }); + expect(env.TMPDIR).toBe("/tmp/custom"); + expect(env.LANG).toBe("en_US.UTF-8"); + }); }); describe("resolveGatewayStateDir", () => { diff --git a/src/daemon/service-env.ts b/src/daemon/service-env.ts index ec6e1a7f3b5..d162de3428a 100644 --- a/src/daemon/service-env.ts +++ b/src/daemon/service-env.ts @@ -214,6 +214,8 @@ export function buildServiceEnvironment(params: { const configPath = env.OPENCLAW_CONFIG_PATH; return { HOME: env.HOME, + TMPDIR: env.TMPDIR, + LANG: env.LANG, PATH: buildMinimalServicePath({ env }), OPENCLAW_PROFILE: profile, OPENCLAW_STATE_DIR: stateDir, @@ -236,6 +238,8 @@ export function buildNodeServiceEnvironment(params: { const configPath = env.OPENCLAW_CONFIG_PATH; return { HOME: env.HOME, + TMPDIR: env.TMPDIR, + LANG: env.LANG, PATH: buildMinimalServicePath({ env }), OPENCLAW_STATE_DIR: stateDir, OPENCLAW_CONFIG_PATH: configPath,