{"record":{"id":"f72652f6993f9436","repo":"helm/helm","slug":"unable-to-read-key-file-q-w","errorCode":null,"errorMessage":"unable to read key file: %q: %w","messagePattern":"unable to read key file: %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tlsutil/tls.go","lineNumber":56,"sourceCode":"\n\t\treturn nil\n\t}\n}\n\nfunc WithCertKeyPairFiles(certFile, keyFile string) TLSConfigOption {\n\treturn func(options *TLSConfigOptions) error {\n\t\tif certFile == \"\" && keyFile == \"\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tcertPEMBlock, err := os.ReadFile(certFile)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to read cert file: %q: %w\", certFile, err)\n\t\t}\n\n\t\tkeyPEMBlock, err := os.ReadFile(keyFile)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to read key file: %q: %w\", keyFile, err)\n\t\t}\n\n\t\toptions.certPEMBlock = certPEMBlock\n\t\toptions.keyPEMBlock = keyPEMBlock\n\n\t\treturn nil\n\t}\n}\n\nfunc WithCAFile(caFile string) TLSConfigOption {\n\treturn func(options *TLSConfigOptions) error {\n\t\tif caFile == \"\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tcaPEMBlock, err := os.ReadFile(caFile)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"can't read CA file: %q: %w\", caFile, err)","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/helm/helm/blob/2a29f1770b62844b27197d2507377361d45ad7c0/internal/tlsutil/tls.go#L38-L74","documentation":"The key-file counterpart of the cert read in WithCertKeyPairFiles: after the cert file reads successfully, os.ReadFile is called on keyFile and any failure is wrapped with the quoted path. The same both-empty guard applies, so setting only the key path makes the option fail here (or earlier on the empty cert path). The wrapped error carries the concrete OS cause.","triggerScenarios":"NewTLSConfig with WithCertKeyPairFiles where keyFile does not exist, is a directory, or is unreadable, or where keyFile is \"\" while certFile is set. Relative key paths resolved from an unexpected working directory also land here.","commonSituations":"Key file held in a secret not mounted at the expected path; key flagged 600 and owned by another user; only --key-file given on the command line; path with a typo or trailing whitespace from a shell variable.","solutions":["Verify the quoted path exists and is readable: ls -l <path>","Supply both cert and key paths together — one without the other is rejected","Prefer absolute paths for credentials","Correct ownership/permissions (e.g., chown/chmod 600 for the key) when the cause is access-related"],"exampleFix":"# before\ncfg, err := tlsutil.NewTLSConfig(tlsutil.WithCertKeyPairFiles(certPath, \"\"))\n\n# after\ncfg, err := tlsutil.NewTLSConfig(tlsutil.WithCertKeyPairFiles(certPath, keyPath))","handlingStrategy":"validation","validationCode":"func validateTLSFilePair(certFile, keyFile string) error {\n\tif (certFile == \"\") != (keyFile == \"\") {\n\t\treturn fmt.Errorf(\"cert and key files must be provided together\")\n\t}\n\tfor _, f := range []string{certFile, keyFile} {\n\t\tif f == \"\" {\n\t\t\treturn nil\n\t\t}\n\t\tif _, err := os.Stat(f); err != nil {\n\t\t\treturn fmt.Errorf(\"stat %s: %w\", f, err)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"cfg, err := tlsutil.NewTLSConfig(tlsutil.WithCertKeyPairFiles(cert, key))\nif err != nil {\n\tvar pathErr *fs.PathError\n\tif errors.As(err, &pathErr) && errors.Is(pathErr, fs.ErrPermission) {\n\t\t// key file present but unreadable by this user: fix ownership/permissions\n\t}\n\treturn err\n}","preventionTips":["Never set only one of the pair — the option requires both or neither","Store key files with 600 permissions owned by the Helm process user","Validate both paths with os.Stat in a preflight check before starting operations"],"tags":["tls","certificates","files","configuration"],"backgroundTag":null,"analyzedSha":"2a29f1770b62844b27197d2507377361d45ad7c0","analyzedAt":"2026-08-15T22:02:47.490Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}