Skip to content

feat(config): add openclaw config validate and improve startup error messages#31220

Merged
gumadeiras merged 6 commits intoopenclaw:mainfrom
Sid-Qin:feat/config-write-validation-31148
Mar 2, 2026
Merged

feat(config): add openclaw config validate and improve startup error messages#31220
gumadeiras merged 6 commits intoopenclaw:mainfrom
Sid-Qin:feat/config-write-validation-31148

Conversation

@Sid-Qin
Copy link
Contributor

@Sid-Qin Sid-Qin commented Mar 2, 2026

Summary

  • Problem: OpenClaw does not validate config at write time for external edits. Invalid keys written to openclaw.json (by agents, jq, text editors) sit undetected until the next gateway restart, causing crash loops. The startup error says "Invalid config" without identifying which key is invalid.
  • Why it matters: In agentic deployments, agents modify config programmatically and have no way to verify the write was valid. One user experienced 28 restart cycles over ~14 minutes from a single unrecognized key.
  • What changed: (1) Added openclaw config validate CLI command for pre-flight config validation without starting the gateway. Supports --json for machine-readable output. (2) Improved the loadConfig error to include specific key paths in the Error message itself.
  • What did NOT change (scope boundary): The existing writeConfigFile validation (which already works for config set/config patch paths) is untouched. No changes to Zod schema strictness — .strict() was already applied to all objects.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  1. New CLI command: openclaw config validate — validates the current config against the active Zod schema, reports all offending key paths, and exits with code 0 (valid) or 1 (invalid).
  2. --json flag: openclaw config validate --json outputs { "valid": true/false, "path": "...", "issues": [...] } for machine consumption. Agents can call this after writing config to detect errors before restart.
  3. Improved error message: loadConfig() now throws with the full validation details in the Error message (e.g. "Invalid config at ~/.openclaw/openclaw.json:\n- agents.defaults.suppressToolErrorWarnings: Unrecognized key(s)"), making crash logs immediately actionable without searching separate log lines.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No — read-only validation, no config modification
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS (Apple M4)
  • Runtime/container: Node.js 22+
  • Model/provider: Any
  • Integration/channel (if any): Any
  • Relevant config (redacted): Standard openclaw.json

Steps

  1. Add an unrecognized key to openclaw.json: { "agents": { "defaults": { "suppressToolErrorWarnings": true } } }
  2. Run openclaw config validate
  3. Observe clear error identifying the exact key path

Expected

  • openclaw config validate exits with code 1 and prints: × agents.defaults.suppressToolErrorWarnings: Unrecognized key(s) in object

Actual

  • Before this PR: No validate subcommand exists. Startup error says "Invalid config" without the key path.
  • After this PR: config validate catches the issue immediately. Startup error includes the key path.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Verified runConfigValidate with valid config (exit 0, "Config valid") and with invalid keys (exit 1, per-key error output). Verified --json mode produces parseable JSON.

Human Verification (required)

  • Verified scenarios: Valid config → exit 0; invalid key → exit 1 with key path; missing config file → exit 1; --json flag produces correct JSON structure.
  • Edge cases checked: Multiple validation issues reported; config file not found; <root> path fallback for top-level errors.
  • What you did not verify: Integration test in a full systemd deployment with crash-loop recovery.

Compatibility / Migration

  • Backward compatible? Yes — additive CLI subcommand, no existing behavior changed.
  • Config/env changes? No
  • Migration needed? No
  • If yes, exact upgrade steps: N/A

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: The validate subcommand is entirely additive. Removing it has no effect on gateway startup or config handling.
  • Files/config to restore: src/cli/config-cli.ts — remove runConfigValidate and the validate subcommand registration.
  • Known bad symptoms reviewers should watch for: None — the command is read-only.

Risks and Mitigations

  • Risk: CONFIG_PATH could resolve to undefined if called before config initialization.
    • Mitigation: Falls back to "openclaw.json" literal. The readConfigFileSnapshot() call itself handles path resolution independently.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 2, 2026

Greptile Summary

This PR adds a openclaw config validate command for pre-flight config validation and improves error messages by including specific key paths in the Error message itself. The implementation is solid and addresses the stated problem of config validation in agentic deployments.

Key Changes:

  • Added runConfigValidate function with --json flag support for machine-readable output
  • Improved loadConfig error message to include path and validation details directly in the Error message
  • New CLI command properly handles missing files, invalid configs, and exceptions with appropriate exit codes

Minor Suggestion:

  • Consider using snapshot.path from the returned snapshot for output messages to ensure the displayed path matches the actual file being validated, especially in edge cases where environment variables or config candidates change between module load and runtime.

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk - it's an additive CLI command that doesn't modify existing behavior
  • Score reflects well-structured implementation with proper error handling, exit codes, and JSON output formatting. One minor suggestion for path display accuracy doesn't impact functionality in typical use cases. The changes are isolated, read-only, and thoroughly address the stated problem.
  • No files require special attention - both changes are straightforward and well-implemented

Last reviewed commit: 88c8737

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +330 to +331
const configPath = CONFIG_PATH ?? "openclaw.json";
const shortPath = shortenHomePath(configPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using snapshot.path instead of CONFIG_PATH for display accuracy. CONFIG_PATH is resolved at module load time, while readConfigFileSnapshot() resolves the path at runtime. If config candidates change or env vars are modified between module load and runtime, the displayed path might not match the actual file being validated. Replace configPath with snapshot.path in outputs (lines 338, 353, 369) and use shortenHomePath(snapshot.path) for lines 340, 355, 371.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cli/config-cli.ts
Line: 330-331

Comment:
Consider using `snapshot.path` instead of `CONFIG_PATH` for display accuracy. `CONFIG_PATH` is resolved at module load time, while `readConfigFileSnapshot()` resolves the path at runtime. If config candidates change or env vars are modified between module load and runtime, the displayed path might not match the actual file being validated. Replace `configPath` with `snapshot.path` in outputs (lines 338, 353, 369) and use `shortenHomePath(snapshot.path)` for lines 340, 355, 371.

How can I resolve this? If you propose a fix, please make it concise.

@gumadeiras gumadeiras self-assigned this Mar 2, 2026
@gumadeiras gumadeiras force-pushed the feat/config-write-validation-31148 branch from 88c8737 to dafee15 Compare March 2, 2026 04:39
@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation app: macos App: macos app: web-ui App: web-ui agents Agent runtime and tooling size: M and removed size: S labels Mar 2, 2026
@gumadeiras gumadeiras force-pushed the feat/config-write-validation-31148 branch from dafee15 to 4dc4103 Compare March 2, 2026 04:42
@openclaw-barnacle openclaw-barnacle bot added size: S and removed app: macos App: macos app: web-ui App: web-ui agents Agent runtime and tooling size: M labels Mar 2, 2026
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4dc41036a0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +341 to +342
const configPath = CONFIG_PATH ?? "openclaw.json";
const shortPath = shortenHomePath(configPath);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use snapshot path for validate output

runConfigValidate reports path and human-readable location from the module-level CONFIG_PATH, but the file actually validated comes from readConfigFileSnapshot() and can differ from that constant (for example when candidate resolution selects another existing config path). In those cases config validate will claim it validated one file while reading another, which can mislead operators and break automation that relies on the emitted path; use snapshot.path for all output/error path fields instead.

Useful? React with 👍 / 👎.

gumadeiras added a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
SidQin-cyber and others added 6 commits March 2, 2026 00:43
…r messages

Add a `config validate` CLI subcommand that checks the current config
against the Zod schema without starting the gateway.  Supports `--json`
for machine-readable output so agents and scripts can validate after
external file edits.

Also improve the error thrown by `loadConfig` to include the specific
offending key paths in the Error message itself, not just as a side
property — making crash logs immediately actionable.

Closes openclaw#31148

Made-with: Cursor
@gumadeiras gumadeiras force-pushed the feat/config-write-validation-31148 branch from 9eb472d to 4598f2a Compare March 2, 2026 05:45
@gumadeiras gumadeiras merged commit 3002f13 into openclaw:main Mar 2, 2026
9 checks passed
@gumadeiras
Copy link
Member

Merged via squash.

Thanks @Sid-Qin!

safzanpirani pushed a commit to safzanpirani/clawdbot that referenced this pull request Mar 2, 2026
…r messages (openclaw#31220)

Merged via squash.

Prepared head SHA: 4598f2a
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
…r messages (openclaw#31220)

Merged via squash.

Prepared head SHA: 4598f2a
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
hanqizheng pushed a commit to hanqizheng/openclaw that referenced this pull request Mar 2, 2026
…r messages (openclaw#31220)

Merged via squash.

Prepared head SHA: 4598f2a
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
…r messages (openclaw#31220)

Merged via squash.

Prepared head SHA: 4598f2a
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
dawi369 pushed a commit to dawi369/davis that referenced this pull request Mar 3, 2026
…r messages (openclaw#31220)

Merged via squash.

Prepared head SHA: 4598f2a
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
aronchick pushed a commit to aronchick/openclaw that referenced this pull request Mar 5, 2026
sachinkundu pushed a commit to sachinkundu/openclaw that referenced this pull request Mar 6, 2026
…r messages (openclaw#31220)

Merged via squash.

Prepared head SHA: 4598f2a
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
…r messages (openclaw#31220)

Merged via squash.

Prepared head SHA: 4598f2a
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
atlastacticalbot pushed a commit to tensakulabs/atlasbot that referenced this pull request Mar 6, 2026
…r messages (openclaw#31220)

Merged via squash.

Prepared head SHA: 4598f2a
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

(cherry picked from commit 3002f13)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes docs Improvements or additions to documentation size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Config write has no validation — invalid keys silently accepted, only caught on gateway restart

2 participants