Skip to content

[Question/Bug]: Validation not working for map fields with struct values containing validation tags #1430

Open
@hi-rai

Description

@hi-rai

What happened?

I'm facing an issue with validating a struct that contains a map field. The map's keys and values need to be validated, but the current setup isn't working as expected.

Struct Definitions

  1. I have a struct Outer with a field Inner that is a map of type map[string]Inner
  2. Outer.Inner is of type Inner and has a single field Value
type Inner struct {
	Value string `validate:"max=5"`
}

type Outer struct {
	Inner map[string]Inner `validate:"dive,keys,max=5,endkeys"`
}

Issue

  1. Current Behavior: Validation does not seem to apply to the map values (Inner structs) as expected.
  2. Workarounds
    a. Adding ,required after endkeys seems to trigger the validation, but it also prevents (with validator.WithRequiredStructEnabled()) empty struct values (Inner{}), which is not the desired behavior.
    b. Removing key validations and retaining only dive also triggers validation on values (but key validations are missed)
  3. Documentation: I did not find any similar mention or examples in the documentation.

Is this a bug ? Or am I supposed to do something differently to achieve my desired behavior ?

Version

v10.26.0

Example Code

package main

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

type Inner struct {
	Value string `validate:"max=5"`
}

type Outer1 struct {
	Inner map[string]Inner `validate:"dive,keys,max=5,endkeys"`
}

type Outer2 struct {
	Inner map[string]Inner `validate:"dive"`
}

type Outer3 struct {
	Inner map[string]Inner `validate:"dive,keys,max=5,endkeys,required"`
}

func main() {
	v := validator.New(validator.WithRequiredStructEnabled())

	// Should fail, but passes
	fmt.Println("Outer1:", v.Struct(Outer1{Inner: map[string]Inner{
		"a": {Value: "1234567890"},
	}}))

	// Should fail, and fails (but there is no validation for keys)
	fmt.Println("Outer2:", v.Struct(Outer2{Inner: map[string]Inner{
		"a": {Value: "1234567890"},
	}}))

	// Should fail, and fails (but has extra required validation, which is not intended)
	fmt.Println("Outer3:", v.Struct(Outer3{Inner: map[string]Inner{
		"a": {Value: "1234567890"},
	}}))

	// Should fail (due to required), but I don't want it to fail
	fmt.Println("Outer3 (a):", v.Struct(Outer3{Inner: map[string]Inner{
		"a": {Value: ""},
	}}))
}

// Actual output:
// Outer1: <nil>
// Outer2: Key: 'Outer2.Inner[a].Value' Error:Field validation for 'Value' failed on the 'max' tag
// Outer3: Key: 'Outer3.Inner[a].Value' Error:Field validation for 'Value' failed on the 'max' tag
// Outer3 (a): Key: 'Outer3.Inner[a]' Error:Field validation for 'Inner[a]' failed on the 'required' tag

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions