Skip to content

[Bug]: macOS LaunchDaemon exec exits immediately with code 1 when service user shell is /usr/bin/false #69077

@stromseth

Description

@stromseth

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

On macOS 15, when OpenClaw Gateway runs as a custom LaunchDaemon under a service user whose shell is /usr/bin/false, exec returns exitCode=1 after 3-10ms and does not execute the target command.

Steps to reproduce

  1. Run OpenClaw Gateway as a custom macOS LaunchDaemon under a dedicated service user.
  2. Use a service user whose login shell is /usr/bin/false.
  3. Do not set SHELL explicitly in the LaunchDaemon EnvironmentVariables.
  4. Run exec against a trivial script such as:
    #!/bin/sh
    exit 42
  5. Observe that OpenClaw returns exitCode=1 in a few milliseconds and the script body is never reached.

Expected behavior

In the same deployment, after explicitly setting SHELL=/bin/sh in the LaunchDaemon environment, the same minimal script returns exitCode=42 and real commands execute successfully.

Actual behavior

OpenClaw returns a completed exec result with exitCode=1, durationMs=3-10ms, and empty output. The target script is never invoked. After explicitly setting SHELL=/bin/sh in the LaunchDaemon plist, the same test script returns exitCode=42 and real commands execute successfully.

OpenClaw version

2026.4.16

Operating system

macOS 15 / Darwin 25.2.0

Install method

npm global

Model

ollama/qwen2.5:7b

Provider / routing chain

OpenClaw Gateway -> local Ollama (qwen2.5:7b)

Additional provider/model setup details

The provider/model setup did not affect reproduction. The failure reproduced with a minimal exec target script and also after temporarily setting tools.exec.security: "full" and tools.exec.ask: "off" to bypass allowlist behavior.

Logs, screenshots, and evidence

Observed tool result:

{
  "status": "completed",
  "exitCode": 1,
  "durationMs": 4,
  "aggregated": "\n\n(Command exited with code 1)"
}


Observed minimal repro script:

#!/bin/sh
exit 42


Observed verification after workaround:
- With `SHELL=/bin/sh` set in the LaunchDaemon environment, the minimal script returned `exitCode=42`, `durationMs=104`
- A real command returned `exitCode=0`, `durationMs=5410`, with valid JSON output

Additional direct evidence:
- `sudo -u _openclaw node -e 'console.log(process.env.SHELL)'` returned `/usr/bin/false`
- The target script did not execute before the workaround; debug logging placed at the first line of the script never ran

Impact and severity

Affected: custom headless macOS LaunchDaemon deployments using a dedicated service user with a non-login shell such as /usr/bin/false
Severity: High for affected setups because exec does not run at all
Frequency: 100% in observed attempts
Consequence: scheduled and interactive exec-based workflows fail while appearing to be normal completed command exits

Additional information

In the affected runtime, process.env.SHELL was /usr/bin/false. After explicitly setting SHELL=/bin/sh in the LaunchDaemon environment, the same repro passed immediately.

This was also isolated from allowlist behavior by temporarily setting tools.exec.security: "full" and tools.exec.ask: "off"; the failure still reproduced before the SHELL workaround.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingbug:behaviorIncorrect behavior without a crash

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions