Bug type
Regression (worked before, now fails)
Summary
Dashboard root returns 404 on Windows when OpenClaw is installed globally with pnpm, because dist/control-ui files are installed as hardlinks and the static UI files are not served.
Steps to reproduce
- On Windows, install OpenClaw globally with:
pnpm add -g openclaw@latest --config.auto-install-peers=false
- Start the gateway.
- Run:
openclaw dashboard --no-open
- Open the printed dashboard URL, for example:
http://127.0.0.1:18789/#token=...
- Observe that:
http://127.0.0.1:18789/health returns 200
http://127.0.0.1:18789/ready returns 200
http://127.0.0.1:18789/__openclaw/control-ui-config.json returns 200
http://127.0.0.1:18789/ returns 404
http://127.0.0.1:18789/index.html returns 404
- Inspect the installed UI file and note that it is a hardlink:
...node_modules/openclaw/dist/control-ui/index.html
Expected behavior
The dashboard URL printed by openclaw dashboard --no-open should open the Control UI successfully, and / should serve the dashboard HTML.
Actual behavior
The gateway is healthy and Control UI config routes are present, but the dashboard root returns 404.
Observed:
/health -> 200
/ready -> 200
/__openclaw/control-ui-config.json -> 200
/ -> 404
/index.html -> 404
As a workaround, copying dist/control-ui to a normal directory and setting gateway.controlUi.root to that directory makes / and /index.html return 200.
OpenClaw version
2026.3.7 (42a1394)
Operating system
Windows 10 x64 (10.0.19045)
Install method
Global install with pnpm: pnpm add -g openclaw@latest --config.auto-install-peers=false
Logs, screenshots, and evidence
Gateway status was healthy while dashboard root still failed.
HTTP evidence:
- `http://127.0.0.1:18789/health` -> `200`
- `http://127.0.0.1:18789/ready` -> `200`
- `http://127.0.0.1:18789/__openclaw/control-ui-config.json` -> `200`
- `http://127.0.0.1:18789/` -> `404`
- `http://127.0.0.1:18789/index.html` -> `404`
The installed file is a hardlink:
PowerShell:
Get-Item "D:\pnpm-global\5\.pnpm\openclaw@2026.3.7_@napi-rs+canvas@0.1.96\node_modules\openclaw\dist\control-ui\index.html" | Format-List FullName,Attributes,LinkType,Target
Output included:
LinkType : HardLink
Node evidence:
const fs = require("fs");
const st = fs.lstatSync("D:/pnpm-global/5/.pnpm/openclaw@2026.3.7_@napi-rs+canvas@0.1.96/node_modules/openclaw/dist/control-ui/index.html");
console.log({ isSymbolicLink: st.isSymbolicLink(), nlink: st.nlink, size: st.size });
Output:
{ isSymbolicLink: false, nlink: 2, size: 692 }
Workaround that fixed it:
1. Copy dist/control-ui to a normal directory
2. Set:
{
"gateway": {
"controlUi": {
"enabled": true,
"root": "C:\\Users\\lp\\.openclaw\\control-ui"
}
}
}
3. Restart gateway
After that:
/ -> 200
/index.html -> 200
/__openclaw/control-ui-config.json -> 200
Impact and severity
- Affected users/systems/channels:
Windows users installing OpenClaw globally with pnpm, especially when dashboard access is needed.
- Severity:
Blocks dashboard/control UI usage, but gateway and channels can still run.
- Frequency:
Deterministic in this environment.
- Consequence:
Users cannot access the dashboard even though the gateway is healthy, which makes onboarding, configuration, and debugging much harder.
Additional information
This does not look like a gateway auth problem or a missing asset build problem.
The Control UI config endpoint is present and returns 200, so the gateway is mounting Control UI-related routes. The failure appears specific to serving static files from the pnpm-installed dist/control-ui directory.
This looks like a Windows + pnpm hardlink interaction with OpenClaw's static file serving / safe-open logic.
I did not verify whether the same issue occurs with:
- npm global install
- the Windows installer
- WSL
- a source checkout
In this environment, overriding gateway.controlUi.root to a copied non-hardlinked directory is a reliable workaround.
Bug type
Regression (worked before, now fails)
Summary
Dashboard root returns 404 on Windows when OpenClaw is installed globally with pnpm, because dist/control-ui files are installed as hardlinks and the static UI files are not served.
Steps to reproduce
pnpm add -g openclaw@latest --config.auto-install-peers=falseopenclaw dashboard --no-openhttp://127.0.0.1:18789/#token=...http://127.0.0.1:18789/healthreturns200http://127.0.0.1:18789/readyreturns200http://127.0.0.1:18789/__openclaw/control-ui-config.jsonreturns200http://127.0.0.1:18789/returns404http://127.0.0.1:18789/index.htmlreturns404...node_modules/openclaw/dist/control-ui/index.htmlExpected behavior
The dashboard URL printed by
openclaw dashboard --no-openshould open the Control UI successfully, and/should serve the dashboard HTML.Actual behavior
The gateway is healthy and Control UI config routes are present, but the dashboard root returns
404.Observed:
/health->200/ready->200/__openclaw/control-ui-config.json->200/->404/index.html->404As a workaround, copying
dist/control-uito a normal directory and settinggateway.controlUi.rootto that directory makes/and/index.htmlreturn200.OpenClaw version
2026.3.7 (42a1394)
Operating system
Windows 10 x64 (10.0.19045)
Install method
Global install with pnpm:
pnpm add -g openclaw@latest --config.auto-install-peers=falseLogs, screenshots, and evidence
Impact and severity
Windows users installing OpenClaw globally with
pnpm, especially when dashboard access is needed.Blocks dashboard/control UI usage, but gateway and channels can still run.
Deterministic in this environment.
Users cannot access the dashboard even though the gateway is healthy, which makes onboarding, configuration, and debugging much harder.
Additional information
This does not look like a gateway auth problem or a missing asset build problem.
The Control UI config endpoint is present and returns
200, so the gateway is mounting Control UI-related routes. The failure appears specific to serving static files from the pnpm-installeddist/control-uidirectory.This looks like a Windows + pnpm hardlink interaction with OpenClaw's static file serving / safe-open logic.
I did not verify whether the same issue occurs with:
In this environment, overriding
gateway.controlUi.rootto a copied non-hardlinked directory is a reliable workaround.