Skip to content

Align excluded_without with its stated multi-field contract - #1621

Open
dylanpulver wants to merge 1 commit into
go-playground:masterfrom
dylanpulver:fix-excluded-without-multi-param
Open

Align excluded_without with its stated multi-field contract#1621
dylanpulver wants to merge 1 commit into
go-playground:masterfrom
dylanpulver:fix-excluded-without-multi-param

Conversation

@dylanpulver

Copy link
Copy Markdown

Fixes Or Enhances

excludedWithout passes the whole parameter to requireCheckFieldKind as one field name, so excluded_without=Field2 Field3 looks up a field literally named "Field2 Field3", never finds it, and falls back to defaultNotFoundValue=true. The field is then excluded unconditionally, whatever Field2 and Field3 hold — a silent wrong answer, not an error.

Its own doc comment says "when any of the other specified fields are not present", and all seven excluded_with*/required_with*/required_without* siblings parse with parseOneOfParam2 and loop. requiredWithout, directly below it, got exactly this fix in #1422; the adjacent twin was not swept.

Measured with Field1 set:

Field2 Field3 before after
set set invalid valid
set absent invalid invalid
absent set invalid invalid
absent absent invalid invalid

Single-parameter behaviour is unchanged (parseOneOfParam2("A")["A"]).

Run back to back: upstream fails the new test, the fix passes, go test ./... is 25/25 ok. A naive variant using excluded_without_all's all-absent loop also fails the new test — that case is what separates the two tags.

Drafted with Claude Opus 5 (claude-opus-5); every claim was executed.

Make sure that you've checked the boxes below before you submit PR:

  • Tests exist or have been written that cover this particular change.

@go-playground/validator-maintainers

excludedWithout passed the whole parameter string to
requireCheckFieldKind as a single field name, so excluded_without=A B
looked up a field literally named "A B", never found it, and fell back
to defaultNotFoundValue=true. The field was therefore excluded
unconditionally, whatever A and B held.

All seven sibling validators (excluded_with, excluded_with_all,
excluded_without_all, required_with, required_with_all,
required_without, required_without_all) parse the parameter with
parseOneOfParam2 and loop. requiredWithout got exactly this fix in
go-playground#1422; its adjacent twin was not swept.
@dylanpulver
dylanpulver requested a review from a team as a code owner September 3, 2026 07:06
@nodivbyzero

Copy link
Copy Markdown
Contributor

Thank you for your contribution!
Could you please rebase your PR against the latest changes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants