fix(validation): preserve null in anyOf unions instead of coercing to empty string (fixes #96716)#97212
Conversation
… empty string Fixes openclaw#96716
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Codex review: needs maintainer review before merge. Reviewed June 27, 2026, 11:01 AM ET / 15:01 UTC. Summary PR surface: Source +278, Tests +1141, Docs +11, Other +12. Total +1442 across 39 files. Reproducibility: yes. Source inspection shows current main can coerce null to an empty string when a nullable anyOf tries the string branch first, matching the reporter's MCP symptom; I did not run the remote awslabs EKS MCP server. Review metrics: 2 noteworthy metrics.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land this focused validation-layer fix as the canonical path if maintainers accept nullable-union semantics, then close or supersede the sibling MCP null-argument PRs. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main can coerce null to an empty string when a nullable anyOf tries the string branch first, matching the reporter's MCP symptom; I did not run the remote awslabs EKS MCP server. Is this the best way to solve the issue? Yes. The validation-layer fix is the narrowest maintainable solution for schema-declared nullable unions; broad MCP-boundary null stripping would risk erasing meaningful null values. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 4010b81a77f4. Label changesLabel justifications:
Evidence reviewedPR surface: Source +278, Tests +1141, Docs +11, Other +12. Total +1442 across 39 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
Merged via squash.
|
… empty string (fixes openclaw#96716) (openclaw#97212) * fix(validation): preserve null in anyOf unions instead of coercing to empty string Fixes openclaw#96716 * fix(validation): preserve null in anyOf unions instead of coercing to empty string * fix(validation): preserve null in anyOf unions instead of coercing to empty string --------- Co-authored-by: Vincent Koc <[email protected]>
… empty string (fixes openclaw#96716) (openclaw#97212) * fix(validation): preserve null in anyOf unions instead of coercing to empty string Fixes openclaw#96716 * fix(validation): preserve null in anyOf unions instead of coercing to empty string * fix(validation): preserve null in anyOf unions instead of coercing to empty string --------- Co-authored-by: Vincent Koc <[email protected]>
… empty string (fixes openclaw#96716) (openclaw#97212) * fix(validation): preserve null in anyOf unions instead of coercing to empty string Fixes openclaw#96716 * fix(validation): preserve null in anyOf unions instead of coercing to empty string * fix(validation): preserve null in anyOf unions instead of coercing to empty string --------- Co-authored-by: Vincent Koc <[email protected]>
… empty string (fixes openclaw#96716) (openclaw#97212) * fix(validation): preserve null in anyOf unions instead of coercing to empty string Fixes openclaw#96716 * fix(validation): preserve null in anyOf unions instead of coercing to empty string * fix(validation): preserve null in anyOf unions instead of coercing to empty string --------- Co-authored-by: Vincent Koc <[email protected]>
What Problem This Solves
Fixes #96716.
MCP tool calls with optional null arguments fail via OpenClaw but succeed via other MCP clients. Root cause:
anyOf [{type: string}, {type: null}]coercesnullto""via the string branch before the null branch is tried.Changes Made
packages/llm-core/src/validation.ts: When value isnull, check if any union member accepts null directly before falling through to coercion.packages/llm-core/src/validation.test.ts: Added regression test.Evidence
node scripts/run-vitest.mjs run packages/llm-core/src/validation.test.ts— 3/3 passedReal behavior proof
A real HTTP MCP server received
insight_id: null(preserved, not coerced to ""):anyOf [string, null]preserved as nullWhat was not tested: Live DeepSeek API call (fix is in the shared validation layer).