{"record":{"id":"76f69be995b38587","repo":"go-playground/validator","slug":"endkeys-tag-encountered-without-a-corresponding","errorCode":null,"errorMessage":"'endkeys' tag encountered without a corresponding 'keys' tag","messagePattern":"'endkeys' tag encountered without a corresponding 'keys' tag","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"cache.go","lineNumber":242,"sourceCode":"\n\t\t\tfor ; i < len(tags); i++ {\n\t\t\t\tb = append(b, tags[i]...)\n\t\t\t\tb = append(b, ',')\n\n\t\t\t\tif tags[i] == endKeysTag {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcurrent.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, \"\", false)\n\n\t\tcase endKeysTag:\n\t\t\tcurrent.typeof = typeEndKeys\n\n\t\t\t// if there are more in tags then there was no keysTag defined\n\t\t\t// and an error should be thrown\n\t\t\tif i != len(tags)-1 {\n\t\t\t\tpanic(keysTagNotDefined)\n\t\t\t}\n\t\t\treturn\n\n\t\tcase omitzero:\n\t\t\tcurrent.typeof = typeOmitZero\n\t\t\tcontinue\n\n\t\tcase omitempty:\n\t\t\tcurrent.typeof = typeOmitEmpty\n\n\t\tcase omitnil:\n\t\t\tcurrent.typeof = typeOmitNil\n\n\t\tcase structOnlyTag:\n\t\t\tcurrent.typeof = typeStructOnly\n\n\t\tcase noStructLevelTag:\n\t\t\tcurrent.typeof = typeNoStructLevel","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/go-playground/validator/blob/facf128d2eecf42bd4ff447adc961aa21bb64aed/cache.go#L224-L260","documentation":"An `endkeys` tag was parsed without a matching `keys` tag in the same tag chain. cache.go panics with keysTagNotDefined (\"'endkeys' tag encountered without a corresponding 'keys' tag\") when `endkeys` appears where no keys block is open (specifically when it is not the terminating tag after a keys block).","triggerScenarios":"Tag like `validate:\"dive,endkeys,required\"` or `validate:\"endkeys\"` — endkeys without keys; also endkeys followed by more tags but no preceding keys.","commonSituations":"Deleting a `keys,...` segment during editing while leaving `endkeys`; misunderstanding of the dive,keys,endkeys pairing for map validation.","solutions":["Ensure every `endkeys` is preceded by `keys` inside a `dive` block: `dive,keys,<...>,endkeys,<...>`","Remove the orphaned `endkeys` tag","Fix generated/aliased tag strings to emit the full keys/endkeys pair","Validate a sample struct in unit tests to catch syntax panics at build time"],"exampleFix":"// before\nM map[string]string `validate:\"dive,endkeys,min=1\"`\n// after\nM map[string]string `validate:\"dive,keys,min=1,endkeys,min=1\"`","handlingStrategy":"validation","validationCode":"func checkEndKeys(t reflect.StructTag) error {\n    tags := strings.Split(t.Get(\"validate\"), \",\")\n    depth := 0\n    for _, tg := range tags {\n        switch tg {\n        case \"keys\": depth++\n        case \"endkeys\":\n            if depth == 0 { return errors.New(\"endkeys without keys\") }\n            depth--\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"invalid tag structure: %v\", r)\n    }\n}()\n_ = validate.Struct(sample)","preventionTips":["Pair every endkeys with a keys inside a dive block","Delete keys and endkeys together during refactors","Add tag-pair linting to CI","Validate a fixture struct per type at init"],"tags":["go","validator","panic","tag-syntax","cache"],"backgroundTag":"validator-invalid-tag-syntax","analyzedSha":"facf128d2eecf42bd4ff447adc961aa21bb64aed","analyzedAt":"2026-09-02T10:19:04.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}