siyuan-note/siyuan · error
failed to write CA certificate: %w
Error message
failed to write CA certificate: %w
What it means
Returned by ImportCABundle when os.WriteFile fails writing caCertPEM to <ConfDir>/ca.crt (mode 0644). The PEM was validated and parsed, but persisting it to disk failed. The error wraps the underlying os PathError so the caller can inspect errno.
Source
Thrown at kernel/util/cert.go:344
if !caCert.IsCA {
return fmt.Errorf("the provided certificate is not a CA certificate")
}
keyBlock, _ := pem.Decode([]byte(caKeyPEM))
if keyBlock == nil {
return fmt.Errorf("failed to decode CA private key PEM")
}
_, err = x509.ParseECPrivateKey(keyBlock.Bytes)
if err != nil {
return fmt.Errorf("failed to parse CA private key: %w", err)
}
caCertPath := filepath.Join(ConfDir, TLSCACertFilename)
caKeyPath := filepath.Join(ConfDir, TLSCAKeyFilename)
if err := os.WriteFile(caCertPath, []byte(caCertPEM), 0644); err != nil {
return fmt.Errorf("failed to write CA certificate: %w", err)
}
if err := os.WriteFile(caKeyPath, []byte(caKeyPEM), 0600); err != nil {
return fmt.Errorf("failed to write CA private key: %w", err)
}
certPath := filepath.Join(ConfDir, TLSCertFilename)
keyPath := filepath.Join(ConfDir, TLSKeyFilename)
if gulu.File.IsExist(certPath) {
os.Remove(certPath)
}
if gulu.File.IsExist(keyPath) {
os.Remove(keyPath)
}
logging.LogInfof("imported CA bundle, server certificate will be regenerated on next TLS initialization")
return nilView on GitHub (pinned to 251596fc0d)
Solutions
- Ensure ConfDir (the workspace conf directory) exists and is writable before importing.
- Free disk space or fix permissions on the conf directory and any existing ca.crt.
- Inspect the wrapped error (errors.Unwrap) for the underlying os error and address that (ENOENT, EROFS, ENOSPC).
Example fix
// before
err := util.ImportCABundle(certPEM, keyPEM) // -> failed to write CA certificate: open .../ca.crt: permission denied
// after
if err := os.MkdirAll(util.ConfDir, 0755); err != nil { return err }
err := util.ImportCABundle(certPEM, keyPEM) Defensive patterns
Strategy: try-catch
Try / catch
if err := util.ImportCABundle(certPEM, keyPEM); err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) || strings.Contains(err.Error(), "failed to write CA certificate") {
// conf dir missing/readonly/full — fix the FS then re-run
os.MkdirAll(util.ConfDir, 0755)
return util.ImportCABundle(certPEM, keyPEM)
}
return err
} Prevention
- Ensure ConfDir exists and is writable before importing.
- Free disk space and fix permissions on the conf directory up front.
- Inspect the wrapped os error to distinguish ENOENT, EROFS, ENOSPC.
When it happens
Trigger: Calling ImportCABundle when the conf directory does not exist, is read-only, the disk is full, or permission on ca.crt denies writing.
Common situations: ConfDir not initialised (kernel not booted); running with insufficient filesystem permissions; read-only deployment; out-of-disk.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to write CA private key: %w
- failed to decode CA certificate PEM
- failed to parse CA certificate: %w
- the provided certificate is not a CA certificate
- write data [%s] failed: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/116a1cb2a417ec24.
Report an issue: GitHub.