kopia/kopia · error
error opening certificate file
Error message
error opening certificate file
What it means
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.
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
Example fix
// before
err := tlsutil.WriteCertificateToFile("/var/lib/app/certs/tls.crt", cert) // fails: dir missing
// after
if err := os.MkdirAll("/var/lib/app/certs", 0o755); err != nil {
return err
}
err := tlsutil.WriteCertificateToFile("/var/lib/app/certs/tls.crt", cert) Defensive patterns
Strategy: try-catch
Validate before calling
func canWriteCertFile(fname string) error {
if fi, err := os.Stat(fname); err == nil && fi.IsDir() {
return fmt.Errorf("%s is a directory", fname)
}
f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, 0o600)
if err != nil { return err }
f.Close()
os.Remove(fname) // only if newly created
return nil
} Type guard
func isFileOpenErr(err error) bool {
return errors.Is(err, os.ErrPermission) || errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.EISDIR)
} Try / catch
if err := tlsutil.WriteCertificateToFile(fname, cert); err != nil {
var pe *fs.PathError
if errors.As(err, &pe) {
log.Printf("cert file %s: %v", pe.Path, pe.Err)
}
return fmt.Errorf("writing certificate: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Failed to write data
- unable to open cache dir marker file
- unable to write WebDAV key
- blob-retention
- cache dir marker file too short
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/2cc927c918f75d65.
Report an issue: GitHub.
Appendix: source
Thrown at internal/tlsutil/tlsutil.go:116
}()
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return errors.Wrap(err, "Unable to marshal private key")
}
if err := pem.Encode(f, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
return errors.Wrap(err, "Failed to write data to")
}
return nil
}
// WriteCertificateToFile writes the certificate to a given file.
func WriteCertificateToFile(fname string, cert *x509.Certificate) (err error) {
f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, certificateFileMode) //nolint:gosec
if err != nil {
return errors.Wrap(err, "error opening certificate file")
}
defer func() {
err = stderrors.Join(err, f.Close())
}()
if err := pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}); err != nil {
return errors.Wrap(err, "Failed to write data")
}
return nil
}
// TLSConfigTrustingSingleCertificate return tls.Config which trusts exactly one TLS certificate with
// provided SHA256 fingerprint.
func TLSConfigTrustingSingleCertificate(sha256Fingerprint string) *tls.Config {
sha256FingerprintBytes, err := hex.DecodeString(sha256Fingerprint)
if err != nil || len(sha256FingerprintBytes) < sha256.Size {View on GitHub (pinned to 82495e54b5)