fix: prevent panic in unique validation with nil pointer elements#1530
fix: prevent panic in unique validation with nil pointer elements#1530veeceey wants to merge 1 commit intogo-playground:masterfrom
Conversation
The `unique` tag panics when validating slices or maps containing nil pointer elements. This affects three code paths in isUnique: slices without a field param, slices with a field param (unique=Field), and maps with pointer values. The fix safely skips nil elements after reflect.Indirect returns a zero Value, and treats multiple nil entries as duplicates (not unique). Fixes go-playground#1319 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Thanks for the contribution! I took a look at your changes - what do you think about treating Then we could keep the original check: |
|
Thanks for the suggestion! I considered that approach but there's a subtle correctness issue — if we use a zero-value key for nil pointers, it would collide with an actual element whose fields are all zero-valued. For example, The |
|
Hey @nodivbyzero, thanks for putting that together! I took a look at #1532. Your approach is definitely cleaner in terms of not needing a separate counter. One thing I noticed though - using That said, I can see the argument that treating nil as equivalent to zero-value might be reasonable depending on the use case. Happy to defer to the maintainers on which behavior they prefer - just wanted to flag the semantic difference. |
|
Hi maintainers, just checking in on this one. I've had a good discussion with @nodivbyzero about the approach (nilCount vs zero-value key). My approach keeps nil tracking separate to avoid collisions between nil pointers and zero-value structs. @nodivbyzero opened an alternative in #1532. Would love a maintainer's take on which semantic approach you prefer — happy to adjust either way! |
|
@veeceey Is there a test case that succeeds on your branch but fails on mine? |
|
@nodivbyzero Yes — consider this test case: type Inner struct {
Name string
}
// A slice with nil and a zero-value struct
s := []*Inner{nil, {Name: ""}}On my branch, this correctly passes the Happy to add this as an explicit test case if that would help illustrate the difference! |
|
@nodivbyzero Yes, exactly like that! That test case would pass on my branch (nil and |
@veeceey this test case has been added in my branch :) |
|
Nice, glad that test case made it in! Sounds like #1532 has converged to handle the nil vs zero-value distinction properly now. Happy to close this one if maintainers prefer that approach — just let me know. |
|
Closing in favor of #1532 which now covers the nil vs zero-value distinction as well. Thanks @nodivbyzero for picking it up! |
) ## Fixes Or Enhances This is an alternative approach to resolve the panic issue in the unique validator. Releated to: #1530 **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
Summary
reflect: call of reflect.Value.FieldByName on zero Value) when theuniquetag validates slices or maps containing nil pointer elements.isUniqueare affected: (1) slices without a field param (unique), (2) slices with a field param (unique=Name), and (3) maps with pointer values. All three now safely handle nil elements.uniquecheck.Fixes #1319
Reproduction
Changes
baked_in.go: In all three branches ofisUnique(slice no-param, slice with-param, map), checke.IsValid()afterreflect.Indirectand skip nil elements with a counter. Return false whennilCount > 1(duplicate nils are not unique).validator_test.go: AddedTestUniqueValidationNilPtrSlicewith 9 sub-tests covering single nil, duplicate nils, and mixed nil/non-nil for all three code paths.Test plan
TestUniqueValidationNilPtrSlicepasses (9 sub-tests)go test ./...-- all 24 packages OK, zero failures)TestUniqueValidation,TestUniqueValidationStructSlice, andTestUniqueValidationStructPtrSlice