{"record":{"id":"157906adc242868a","repo":"k3s-io/k3s","slug":"invalid-gvk-format-s","errorCode":null,"errorMessage":"invalid GVK format: %s","messagePattern":"invalid GVK format: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/deploy/controller.go","lineNumber":534,"sourceCode":"\t\tsubPath := filepath.Join(namePath[0:i]...)\n\t\tif disables[subPath] {\n\t\t\treturn true\n\t\t}\n\t}\n\tif !util.HasSuffixI(fileName, \".yaml\", \".yml\", \".json\") {\n\t\treturn false\n\t}\n\t// Check the basename against the disables map\n\tbaseFile := filepath.Base(fileName)\n\tsuffix := filepath.Ext(baseFile)\n\tbaseName := strings.TrimSuffix(baseFile, suffix)\n\treturn disables[baseName]\n}\n\nfunc getGVK(s string) (*schema.GroupVersionKind, error) {\n\tparts := strings.Split(s, \", Kind=\")\n\tif len(parts) != 2 {\n\t\treturn nil, fmt.Errorf(\"invalid GVK format: %s\", s)\n\t}\n\tgvk := &schema.GroupVersionKind{}\n\tgvk.Group, gvk.Version = kv.Split(parts[0], \"/\")\n\tgvk.Kind = parts[1]\n\treturn gvk, nil\n}\n\nfunc getGVKString(gvks []schema.GroupVersionKind) string {\n\tstrs := make([]string, len(gvks))\n\tfor i, gvk := range gvks {\n\t\tstrs[i] = gvk.String()\n\t}\n\treturn strings.Join(strs, gvkSep)\n}\n","sourceCodeStart":516,"sourceCodeEnd":549,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/deploy/controller.go#L516-L549","documentation":"getGVK parses strings produced by schema.GroupVersionKind.String(), i.e. exactly 'group/version, Kind=Kind' ('apps/v1, Kind=Deployment'). It splits on the literal ', Kind=' and requires exactly one separator; anything else is rejected. It is used to parse the GVK annotation k3s stores on auto-deployed manifest Addons. Note: both call sites (pkg/deploy/controller.go:256, 303) discard this error via `if gvk, err := getGVK(...); err == nil`, so in shipped k3s the error never propagates - it only fires for direct callers (e.g. tests).","triggerScenarios":"Invoking getGVK with a string lacking the ', Kind=' separator or containing it more than once, e.g. 'apps/v1', 'Deployment', or 'apps/v1, Kind=Deployment, Kind=Pod' (pkg/deploy/controller.go:531-538). In-cluster, only a hand-edited GVK annotation on an Addon object would carry such a value.","commonSituations":"Manually editing the auto-deployed Addon annotations (kubectl annotate addons ...); a script writing GVK strings in a different format; unit tests feeding unstructured GVK strings.","solutions":["Keep GVK strings in the canonical GroupVersionKind.String() format: 'group/version, Kind=Kind'.","Let k3s manage the GVK annotation itself - it is written by getGVKString after each successful apply; delete a corrupt annotation and let the controller rewrite it.","If calling getGVK from code, validate/normalize the input first instead of relying on the error."],"exampleFix":"// before\naddon.Annotations[\"deploy.k3s.cattle.io/gvks\"] = \"apps/v1 Deployment\"\n\n// after\naddon.Annotations[\"deploy.k3s.cattle.io/gvks\"] = \"apps/v1, Kind=Deployment\"","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Narrow a string to a valid GroupVersionKind String() before parsing:\nfunc isGVKString(s string) bool {\n    parts := strings.Split(s, \", Kind=\")\n    if len(parts) != 2 { return false }\n    seg := strings.Split(parts[0], \"/\")\n    if len(seg) < 1 || len(seg) > 2 { return false } // 'v1' or 'group/version'\n    return parts[0] != \"\" && parts[1] != \"\"\n}\n\nif isGVKString(s) { gvk, _ := getGVK(s) }","tryCatchPattern":"// Follow the controller's own pattern - skip invalid entries instead of failing:\nif gvk, err := getGVK(gvkString); err == nil {\n    addonGVKs = append(addonGVKs, *gvk)\n} else {\n    log.Warnf(\"ignoring malformed GVK %q: %v\", gvkString, err)\n}","preventionTips":["Only use schema.GroupVersionKind.String() output as annotation values.","Treat k3s-managed Addon annotations as controller-owned; change manifests, not annotations.","In tests, generate GVK strings from the struct rather than literals."],"tags":["manifests","deploy","gvk","addon","parsing"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}