Description
Running openclaw gateway install on Windows creates a Scheduled Task. After installation, openclaw gateway status reports:
Service config issue: Service command does not include the gateway subcommand
Command: setlocal enabledelayedexpansion
Service file: C:\Users\<username>\.openclaw\gateway.cmd
Steps to reproduce
- Run
openclaw gateway install
- Run
openclaw gateway status or openclaw doctor
Expected behavior
No audit warnings; the gateway service configuration is validated successfully.
Actual behavior
openclaw gateway status reports a gatewayCommandMissing audit issue.
Root Cause
The bug is in src/daemon/schtasks.ts → readScheduledTaskCommand().
How the function works
readScheduledTaskCommand() reads gateway.cmd, iterates line by line, skips @echo off, rem comments, and set environment lines (checking if (lower.startsWith("set "))), then captures the first real executable line as the command:
@echo off
setlocal enabledelayedexpansion
set "PORT=18789"
set "NODE=C:\Program Files\nodejs\node.exe"
set "SCRIPT=..."
...
start "" "%NODE%" "%SCRIPT%" gateway --port %PORT%
The bug
The parser checks if (lower.startsWith("set ")) — note the trailing space. setlocal does NOT start with set (it starts with setlocal), so setlocal enabledelayedexpansion is not skipped. It is incorrectly captured as the first executable line → commandLine = "setlocal enabledelayedexpansion".
This is passed to parseCmdScriptCommandLine(), producing:
programArguments: ["setlocal", "enabledelayedexpansion"]
The audit check
In systemd-hints.ts:
function hasGatewaySubcommand(programArguments) {
return Boolean(programArguments?.some((arg) => arg === "gateway"));
}
Since neither "setlocal" nor "enabledelayedexpansion" equals "gateway", hasGatewaySubcommand() returns false → false positive gatewayCommandMissing audit error.
The actual task is fine
schtasks /query /fo LIST correctly shows C:\Users\...\gateway.cmd as the task's Program. The gateway runs correctly — this is purely a validation/audit false positive caused by the batch file parsing logic.
The Fix
In src/daemon/schtasks.ts, readScheduledTaskCommand():
// Before:
if (lower.startsWith("set ")) {
// After:
if (lower.startsWith("set ") || lower.startsWith("setlocal")) {
This ensures setlocal enabledelayedexpansion is correctly treated as a batch environment declaration and skipped, allowing the actual start "" "%NODE%" "%SCRIPT%" gateway --port %PORT% line to be captured.
Environment
- OS: Windows 10.0.22631 (x64)
- Username: any (non-ASCII username is NOT required to reproduce)
- OpenClaw version: 2026.3.23-2
- Node.js: 24.14.0
Description
Running
openclaw gateway installon Windows creates a Scheduled Task. After installation,openclaw gateway statusreports:Steps to reproduce
openclaw gateway installopenclaw gateway statusoropenclaw doctorExpected behavior
No audit warnings; the gateway service configuration is validated successfully.
Actual behavior
openclaw gateway statusreports agatewayCommandMissingaudit issue.Root Cause
The bug is in
src/daemon/schtasks.ts→readScheduledTaskCommand().How the function works
readScheduledTaskCommand()readsgateway.cmd, iterates line by line, skips@echo off,remcomments, andsetenvironment lines (checkingif (lower.startsWith("set "))), then captures the first real executable line as the command:The bug
The parser checks
if (lower.startsWith("set "))— note the trailing space.setlocaldoes NOT start withset(it starts withsetlocal), sosetlocal enabledelayedexpansionis not skipped. It is incorrectly captured as the first executable line →commandLine = "setlocal enabledelayedexpansion".This is passed to
parseCmdScriptCommandLine(), producing:programArguments: ["setlocal", "enabledelayedexpansion"]The audit check
In
systemd-hints.ts:Since neither
"setlocal"nor"enabledelayedexpansion"equals"gateway",hasGatewaySubcommand()returnsfalse→ false positivegatewayCommandMissingaudit error.The actual task is fine
schtasks /query /fo LISTcorrectly showsC:\Users\...\gateway.cmdas the task's Program. The gateway runs correctly — this is purely a validation/audit false positive caused by the batch file parsing logic.The Fix
In
src/daemon/schtasks.ts,readScheduledTaskCommand():This ensures
setlocal enabledelayedexpansionis correctly treated as a batch environment declaration and skipped, allowing the actualstart "" "%NODE%" "%SCRIPT%" gateway --port %PORT%line to be captured.Environment