Issue description
- The
zOneOf helper incorrectly reports errors when exactly one of two fields is filled. It should only error when both are filled or both are empty.
- Location: src/utils/zod.ts, function
zOneOf(...).
- Root Cause: The code uses
xor(arg[key1] as boolean, arg[key2] as boolean) and treats that as an error case. xor is true when exactly one input is truthy; the function should error only when “not exactly one” is filled (both or neither). Raw boolean coercion is also fragile for “filled” detection (e.g., empty strings vs. undefined).
Expected behavior
- Validation passes when exactly one of the two keys is “filled” per schema rules.
- Validation fails when both keys are filled or when neither key is filled.
How to Reproduce
Code-based reproduction
import { z } from 'zod';
import { zOneOf } from '@/utils/zod';
// Treat "filled" as non-empty string for this example
const schema = z
.object({ a: z.string().optional(), b: z.string().optional() })
.superRefine(zOneOf<{ a?: string; b?: string }, 'a', 'b'>('a', 'b'));
// Case 1: only a filled → should pass, currently fails
const res1 = schema.safeParse({ a: 'x', b: undefined });
// Case 2: only b filled → should pass, currently fails
const res2 = schema.safeParse({ a: undefined, b: 'y' });
// Case 3: both filled → should fail, may pass
const res3 = schema.safeParse({ a: 'x', b: 'y' });
// Case 4: neither filled → should fail, may pass
const res4 = schema.safeParse({ a: undefined, b: undefined });
// Expected:
// res1.success === true
// res2.success === true
// res3.success === false
// res4.success === false
UI-based reproduction (if a form uses one-of semantics)
- Open any form that requires exactly one of two fields (e.g., a mutually exclusive pair).
- Fill only the first field and leave the second empty.
- Submit the form.
- Observe an error raised on both fields, contradicting the intended “exactly one” rule.
Screenshots
No response
Environment
- apisix version (cmd:
apisix version): N/A (services not running locally)
- OS: Microsoft Windows 11 Home Single Language, 10.0.26200 Build 26200
- OpenResty / Nginx version (cmd:
nginx -V or openresty -V): N/A (services not running locally)
- etcd version, if have (cmd: run
etcd --version): N/A (services not running locally)
- apisix-dashboard version, if have: master branch, commit bbe05ad (package.json version 0.0.0)
- Browser version, if have: Google Chrome 144.0.7559.110
Additional context
I can open a PR to fix this and add unit tests.
Issue description
zOneOfhelper incorrectly reports errors when exactly one of two fields is filled. It should only error when both are filled or both are empty.zOneOf(...).xor(arg[key1] as boolean, arg[key2] as boolean)and treats that as an error case.xoristruewhen exactly one input is truthy; the function should error only when “not exactly one” is filled (both or neither). Raw boolean coercion is also fragile for “filled” detection (e.g., empty strings vs.undefined).Expected behavior
How to Reproduce
Code-based reproduction
UI-based reproduction (if a form uses one-of semantics)
Screenshots
No response
Environment
apisix version): N/A (services not running locally)nginx -Voropenresty -V): N/A (services not running locally)etcd --version): N/A (services not running locally)Additional context
I can open a PR to fix this and add unit tests.