#10807: fix(config): coerce numeric meta.lastTouchedAt to ISO string
size: S
trusted-contributor
experienced-contributor
Cluster:
Config Fixes and Features
## Summary
Fixes #10785
When the agent edits `openclaw.json` directly (bypassing `stampConfigVersion()`), it can write `meta.lastTouchedAt` as a numeric Unix timestamp (e.g. `1770394758161`) instead of an ISO 8601 string. This causes Zod schema validation to reject the config on next startup, preventing the gateway and TUI from launching. The `doctor --fix` command also can't recover because validation fails before any fix logic runs.
**Root cause:** The Zod schema defined `lastTouchedAt: z.string().optional()`, rejecting numeric values.
**Fix:** Accept both strings and numbers via `z.union()`, coercing valid numeric timestamps to ISO strings via `.transform()`. Out-of-range numbers (e.g. `1e20`) are reported as validation errors via `ctx.addIssue()` instead of throwing, preserving `safeParse` error-reporting behavior.
## Changes
- `src/config/zod-schema.ts`: Replace `z.string().optional()` with a `z.union([z.string(), z.number().transform(...)])` that safely coerces valid numeric timestamps to ISO strings
- `src/config/config.meta-timestamp-coercion.test.ts`: 4 new tests covering numeric coercion, string passthrough, out-of-range rejection, and absent field
## Test plan
- [x] Write failing test reproducing the bug (numeric timestamp rejected)
- [x] All 4 new tests fail before fix, pass after
- [x] Out-of-range numeric timestamps (e.g. `1e20`) return `{ ok: false }` instead of throwing `RangeError`
- [x] Full CI gate passes locally (`pnpm build && pnpm check && pnpm test` — 219 tests, 0 failures)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
- Updates `OpenClawSchema` to accept `meta.lastTouchedAt` as either a string or a numeric Unix timestamp, coercing valid numbers to ISO strings during validation.
- Adds a new Vitest suite validating numeric coercion, string passthrough, out-of-range numeric rejection, and optional-field behavior.
- Change is localized to config schema validation and a focused regression test for startup validation failures caused by agent-written configs.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- Changes are narrowly scoped to config schema validation and add regression tests. The coercion uses Zod issues (not throws) to preserve safeParse behavior, and string inputs remain backward-compatible as before.
- No files require special attention
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#12499: fix(config): add missing customBindHost to gateway Zod schema
by sfo2001 · 2026-02-09
79.6%
#10943: fix(config): resolve Control UI "Unsupported schema node" for confi...
by kraftbj · 2026-02-07
79.1%
#16412: fix(config): align tools.web.fetch schema with firecrawl/readabilit...
by ciberponk · 2026-02-14
78.6%
#9670: fix: handle numeric string timestamps in cron schedule normalizatio...
by divol89 · 2026-02-05
77.6%
#14934: fix: add mistral to MemorySearchSchema provider/fallback unions
by ThomsenDrake · 2026-02-12
76.9%
#19429: Fix/custom bind host validation
by frudas24 · 2026-02-17
76.6%
#19401: fix(ui): prevent precision loss when coercing large numeric strings...
by Operative-001 · 2026-02-17
76.2%
#10197: fix: add missing allowAgents to agent defaults subagents schema
by Yida-Dev · 2026-02-06
76.2%
#11602: fix(config): skip stale legacy config files when openclaw.json exists
by akoscz · 2026-02-08
75.9%
#22557: fix(discord): coerce exec approval approver IDs to string to preven...
by zwffff · 2026-02-21
75.7%