{"record":{"id":"898c2ef1b86a67d1","repo":"kubernetes/kops","slug":"asbytes-called-on-nil-private-key","errorCode":null,"errorMessage":"AsBytes called on nil private key","messagePattern":"AsBytes called on nil private key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/pki/privatekey.go","lineNumber":96,"sourceCode":"\nfunc (k *PrivateKey) AsString() (string, error) {\n\t// Nicer behaviour because this is called from templates\n\tif k == nil {\n\t\treturn \"\", fmt.Errorf(\"AsString called on nil private key\")\n\t}\n\n\tvar data bytes.Buffer\n\t_, err := k.WriteTo(&data)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error writing SSL private key: %v\", err)\n\t}\n\treturn data.String(), nil\n}\n\nfunc (k *PrivateKey) AsBytes() ([]byte, error) {\n\t// Nicer behaviour because this is called from templates\n\tif k == nil {\n\t\treturn nil, fmt.Errorf(\"AsBytes called on nil private key\")\n\t}\n\n\tvar data bytes.Buffer\n\t_, err := k.WriteTo(&data)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error writing SSL PrivateKey: %v\", err)\n\t}\n\treturn data.Bytes(), nil\n}\n\nfunc (k *PrivateKey) UnmarshalJSON(b []byte) (err error) {\n\ts := \"\"\n\tif err := json.Unmarshal(b, &s); err == nil {\n\t\tr, err := parsePEMPrivateKey([]byte(s))\n\t\tif err != nil {\n\t\t\t// Alternative form: Check if base64 encoded\n\t\t\t// TODO: Do we need this?  I think we need this only on nodeup, but maybe we could just not base64-it?\n\t\t\td, err2 := base64.StdEncoding.DecodeString(s)","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/pki/privatekey.go#L78-L114","documentation":"PrivateKey.AsBytes() is a nil-receiver guard: since AsBytes is commonly invoked from Go templates where a nil *PrivateKey can slip through silently, the method explicitly returns this error instead of panicking when called on a nil pointer. It means the code path reached serialization without ever having loaded, generated, or assigned a key.","triggerScenarios":"Calling AsBytes() on a *PrivateKey that is nil, e.g. a struct field never populated after ParsePEMPrivateKey returned (nil, nil) for empty input, or a template referencing {{ .Key.AsBytes }} where .Key was never set.","commonSituations":"Templating (yaml/gotemplate) rendering of resources whose key material was not generated because generation was skipped in dry-run; callers ignoring that ParsePEMPrivateKey can return a nil key with nil error on empty data; keys dropped during struct copy or partial initialization.","solutions":["Check for nil before calling: if k == nil or k.Key == nil, generate a key first (GeneratePrivateKey) or return a clear upstream error.","Verify ParsePEMPrivateKey results: it returns (nil, nil) when input is empty — treat nil key as an error at load time instead of passing it along.","Ensure the struct field holding *PrivateKey is populated before template rendering / serialization runs."],"exampleFix":"// before\nkey, _ := pki.ParsePEMPrivateKey(data)\nout, _ := key.AsBytes()\n// after\nkey, err := pki.ParsePEMPrivateKey(data)\nif err != nil { return err }\nif key == nil { return fmt.Errorf(\"no private key present in input\") }\nout, err := key.AsBytes()\nif err != nil { return err }","handlingStrategy":"type-guard","validationCode":"if key == nil || key.Key == nil {\n    return fmt.Errorf(\"private key not initialized\")\n}","typeGuard":"func hasKey(k *pki.PrivateKey) bool { return k != nil && k.Key != nil }","tryCatchPattern":"b, err := key.AsBytes()\nif err != nil {\n    return fmt.Errorf(\"serializing private key: %w\", err)\n}","preventionTips":["Always check the (key, err) pair from ParsePEMPrivateKey — it can return (nil, nil).","Populate key fields immediately after struct construction, before any template rendering.","In templates, guard with a nil check before calling AsBytes."],"tags":["pki","nil-pointer","private-key"],"backgroundTag":"nil-private-key","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}