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 nil

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Ensure ConfDir (the workspace conf directory) exists and is writable before importing.
  2. Free disk space or fix permissions on the conf directory and any existing ca.crt.
  3. 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

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

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/116a1cb2a417ec24. Report an issue: GitHub.