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 <tianrun.yang103@gmail.com>
This commit is contained in:
Clawborn 2026-02-19 09:27:20 +08:00
parent c2b6f099c6
commit 296d5ede68
2 changed files with 37 additions and 0 deletions

View File

@ -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", () => {

View File

@ -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,