{"record":{"id":"6e6ee16dd18628d9","repo":"kubernetes/kops","slug":"asstring-called-on-nil-private-key","errorCode":null,"errorMessage":"AsString called on nil private key","messagePattern":"AsString called on nil private key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/pki/privatekey.go","lineNumber":82,"sourceCode":"\t}\n\n\trsaKey, err := rsa.GenerateKey(crypto_rand.Reader, rsaKeySize)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error generating RSA private key: %v\", err)\n\t}\n\n\tprivateKey := &PrivateKey{Key: rsaKey}\n\treturn privateKey, nil\n}\n\ntype PrivateKey struct {\n\tKey crypto.Signer\n}\n\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)","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/pki/privatekey.go#L64-L100","documentation":"PrivateKey.AsString defensively checks for a nil receiver because it is invoked from Go templates, where a missing value often surfaces as a nil pointer. Instead of panicking on k.WriteTo, it returns this descriptive error so template rendering fails with a clear message.","triggerScenarios":"Calling AsString on a *PrivateKey that is nil — typically when a template references a key that was never generated or loaded (e.g. nil result of a failed/absent keypair lookup passed into a template).","commonSituations":"Rendering nodeup/cluster templates where the private key task was skipped or its keystore lookup returned nil; building kubecfg credentials when a keyset entry is missing.","solutions":["Fix the upstream lookup so a real *PrivateKey is passed (generate/restore the keypair before rendering).","Add a caller-side nil check before invoking AsString.","Verify the keyset for the cluster contains the expected private key entry."],"exampleFix":"// before\nkeyStr, _ := privateKey.AsString()\n// after\nif privateKey == nil {\n    return fmt.Errorf(\"private key not available\")\n}\nkeyStr, err := privateKey.AsString()","handlingStrategy":"type-guard","validationCode":"if privateKey == nil {\n    return fmt.Errorf(\"cannot render: private key not generated\")\n}","typeGuard":"func (k *PrivateKey) IsNil() bool { return k == nil }","tryCatchPattern":"s, err := privateKey.AsString()\nif err != nil {\n    if strings.Contains(err.Error(), \"nil private key\") {\n        // regenerate key then retry template render\n    }\n    return err\n}","preventionTips":["Generate/load keys before executing templates","Check keypair lookup errors instead of ignoring nil results","Assert non-nil keys in template data builders"],"tags":["pki","nil-pointer","private-key","templates"],"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-12T12:17:11.808Z"}