Skip to content

openclaw config set reports success but writes a stub file to /root/.openclaw/, not the gateway-visible /sandbox/.openclaw/openclaw.json #1973

@davidglogan

Description

@davidglogan

openclaw config set reports a successful update and prints "Restart the gateway to apply", but it writes a brand-new minimal JSON file to /root/.openclaw/openclaw.json instead of merging into the gateway-visible config at /sandbox/.openclaw/openclaw.json. The gateway never sees the change. There is no warning, no error, and no indication that two different config files exist.

Environment

  • NemoClaw v0.0.17, OpenShell v0.0.26, OpenClaw v2026.4.2
  • Sandbox host: DietPi2 (Intel Core i7-10710U, 64GB RAM, no discrete GPU, DietPi/Debian)
  • Inference: Ollama 0.20.7-rocm on AMD Ryzen AI 9 HX 370 (Radeon 890M iGPU, 32GB shared VRAM), MicroK8s
  • Provider: compatible-endpoint
  • Sandbox user: sandbox
  • Reproduced 2026-04-16 against the running sandbox

Steps to reproduce

# Inside the sandbox (via openshell sandbox exec or nemoclaw connect)
openclaw config set diagnostics.enabled true
# Output:
#   Updated diagnostics.enabled. Restart the gateway to apply.

The CLI exits 0 and reports success.

# Check the gateway-visible config -- the place the gateway actually reads
cat /sandbox/.openclaw/openclaw.json | head -3
# Output:
#   {
#     "agents": {
#       "defaults": {
# (full config unchanged; no diagnostics field added)

# Check /root/.openclaw/ -- where the CLI actually wrote
ls -la /root/.openclaw/openclaw.json
# Output:
#   -rw------- 1 root root 150 Apr 16 15:39 /root/.openclaw/openclaw.json

cat /root/.openclaw/openclaw.json
# Output:
#   {
#     "diagnostics": {
#       "enabled": true
#     },
#     "meta": {
#       "lastTouchedVersion": "2026.4.2",
#       "lastTouchedAt": "2026-04-16T15:39:56.830Z"
#     }
#   }

The CLI did not merge into the existing config; it wrote a fresh 150-byte stub file containing only the field the user set, plus a meta block. Even if the gateway were pointed at this path, every other config field would be lost.

Expected behavior

openclaw config set <field> <value> should either:

  • Update the gateway-visible config at /sandbox/.openclaw/openclaw.json (preserving all other fields), or
  • Refuse to run with a clear message that config is immutable inside the sandbox and point users at the supported alternative (NEMOCLAW_* env vars + nemoclaw onboard --resume, per @prekshivyas on #719).

Actual behavior

The CLI silently writes a stub file to a path the gateway never reads. The user is told to "restart the gateway to apply" -- doing so changes nothing, because the new stub at /root/.openclaw/ is not on any gateway read path.

Likely cause

openclaw config set appears to resolve the config path via $HOME/.openclaw/openclaw.json. When run under the sandbox user the home should be /sandbox, but something in the CLI's path resolution falls back to /root (possibly an inherited HOME=/root env var from the gateway / startup script, or a hard-coded fallback in the CLI). Either way, the write target is decoupled from the read target.

The stub-only write (no merge from existing config) suggests the CLI isn't even attempting to read the current config before writing -- it constructs a minimal JSON object with just the new field and writes it.

Related context

Workaround

Edit the config from the host via kubectl, which bypasses the in-sandbox CLI entirely:

docker exec openshell-cluster-nemoclaw kubectl exec -n openshell my-assistant -c agent -- \
  sh -c 'cat > /sandbox/.openclaw/openclaw.json <<EOF2
<full json contents here>
EOF2'

This works today because:

  1. kubectl exec runs in a root context, so DAC root ownership of /sandbox/.openclaw/ does not block the write (see openclaw.json created as root with read-only permissions, making all config writes impossible from sandbox #719 for the chown alternative).
  2. Landlock is not enforced on OpenShell 0.0.26 ([All Platform][Security]OpenShell 0.0.26 does not enforce Landlock filesystem policy — /sandbox writable on all platforms #1739), so the kernel does not block the write either.

Once OpenShell 0.0.29+ ships in NemoClaw, this workaround will need to be revised (likely to write outside the sandbox process tree).

Suggested fixes

If config immutability is intentional (per #719):

  1. Make openclaw config set refuse to run inside the sandbox with an actionable message: "Config is immutable inside the sandbox. Use NEMOCLAW_* env vars or 'nemoclaw onboard --resume'. See <link to docs/security/best-practices.md>." Better to surface the design constraint than to ship a CLI that misleads users with success messages.
  2. Apply the same treatment to the GUI settings panel. The panel currently shows pending changes (e.g., agents.list: undefined -> [...]) that will never be applied, with no indication why.

If openclaw config set is meant to work for some subset of fields:

  1. Fix the path resolution so writes target /sandbox/.openclaw/openclaw.json, not /root/.openclaw/openclaw.json. The current behaviour writes a stub that is never read by anything.
  2. Merge into the existing config rather than writing a 150-byte stub that drops every other field.
  3. Document which fields are writable at runtime and which require an onboard rebuild.

Impact

  • Users who follow the README's openclaw config set examples get a "success" message and a "restart the gateway to apply" hint. Doing so changes nothing.
  • Debugging is hard because there are no errors, no warnings, and no diagnostic output -- just a config that never updates.
  • The wrong-path stub at /root/.openclaw/openclaw.json accumulates touched fields over time, none of which take effect. There is no way to discover this without inspecting the filesystem.
  • Once the OpenShell 0.0.29+ Landlock fix lands in NemoClaw, this same CLI will start failing with EACCES against the correct path, but the path resolution bug means the failure mode will still be confusing without first fixing the wrong-path issue.

Metadata

Metadata

Assignees

Labels

area: sandboxOpenShell sandbox lifecycle, runtime, config, or recoveryintegration: openclawOpenClaw integration behavior

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions