{"record":{"id":"2cc927c918f75d65","repo":"kopia/kopia","slug":"error-opening-certificate-file","errorCode":null,"errorMessage":"error opening certificate file","messagePattern":"error opening certificate file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tlsutil/tlsutil.go","lineNumber":116,"sourceCode":"\t}()\n\n\tprivBytes, err := x509.MarshalPKCS8PrivateKey(priv)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"Unable to marshal private key\")\n\t}\n\n\tif err := pem.Encode(f, &pem.Block{Type: \"PRIVATE KEY\", Bytes: privBytes}); err != nil {\n\t\treturn errors.Wrap(err, \"Failed to write data to\")\n\t}\n\n\treturn nil\n}\n\n// WriteCertificateToFile writes the certificate to a given file.\nfunc WriteCertificateToFile(fname string, cert *x509.Certificate) (err error) {\n\tf, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, certificateFileMode) //nolint:gosec\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"error opening certificate file\")\n\t}\n\n\tdefer func() {\n\t\terr = stderrors.Join(err, f.Close())\n\t}()\n\n\tif err := pem.Encode(f, &pem.Block{Type: \"CERTIFICATE\", Bytes: cert.Raw}); err != nil {\n\t\treturn errors.Wrap(err, \"Failed to write data\")\n\t}\n\n\treturn nil\n}\n\n// TLSConfigTrustingSingleCertificate return tls.Config which trusts exactly one TLS certificate with\n// provided SHA256 fingerprint.\nfunc TLSConfigTrustingSingleCertificate(sha256Fingerprint string) *tls.Config {\n\tsha256FingerprintBytes, err := hex.DecodeString(sha256Fingerprint)\n\tif err != nil || len(sha256FingerprintBytes) < sha256.Size {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/internal/tlsutil/tlsutil.go#L98-L134","documentation":"WriteCertificateToFile wraps any error returned by os.OpenFile when it cannot open (or create/truncate) the target certificate file. The library throws it so callers writing a generated x509 certificate to disk get a single descriptive error carrying the underlying OS reason. It is a filesystem-level failure, not a certificate problem.","triggerScenarios":"Calling WriteCertificateToFile when the directory of fname does not exist, the process lacks write permission, fname is a directory, the path is too long, or the filesystem is read-only/full.","commonSituations":"Configured TLS cert dir was never created before startup; running in a container with a read-only rootfs; wrong path in config (e.g. missing /tmp prefix); running as non-root user in a directory owned by root; SELinux/AppArmor blocking file creation.","solutions":["Create the parent directory (os.MkdirAll(filepath.Dir(fname), 0o755)) before calling WriteCertificateToFile","Check and fix filesystem permissions so the process user can create the file (ls -ld on the directory)","Verify fname points to a file path, not an existing directory, and that the filesystem is writable","Inspect the wrapped OS error (permission denied / no such file / read-only) to target the exact cause"],"exampleFix":"// before\nerr := tlsutil.WriteCertificateToFile(\"/var/lib/app/certs/tls.crt\", cert) // fails: dir missing\n\n// after\nif err := os.MkdirAll(\"/var/lib/app/certs\", 0o755); err != nil {\n\treturn err\n}\nerr := tlsutil.WriteCertificateToFile(\"/var/lib/app/certs/tls.crt\", cert)","handlingStrategy":"try-catch","validationCode":"func canWriteCertFile(fname string) error {\n\tif fi, err := os.Stat(fname); err == nil && fi.IsDir() {\n\t\treturn fmt.Errorf(\"%s is a directory\", fname)\n\t}\n\tf, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, 0o600)\n\tif err != nil { return err }\n\tf.Close()\n\tos.Remove(fname) // only if newly created\n\treturn nil\n}","typeGuard":"func isFileOpenErr(err error) bool {\n\treturn errors.Is(err, os.ErrPermission) || errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.EISDIR)\n}","tryCatchPattern":"if err := tlsutil.WriteCertificateToFile(fname, cert); err != nil {\n\tvar pe *fs.PathError\n\tif errors.As(err, &pe) {\n\t\tlog.Printf(\"cert file %s: %v\", pe.Path, pe.Err)\n\t}\n\treturn fmt.Errorf(\"writing certificate: %w\", err)\n}","preventionTips":["Always os.MkdirAll the cert directory at startup before writing certificates","Run the service with a dedicated user that owns the cert directory","Check that config paths end in file names, not directories","Mount persistent writable volumes for cert storage in containers"],"tags":["filesystem","tls","file-open-failed"],"backgroundTag":"file-open-failed","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}