OpenNHP/opennhp · critical

fail to write public key file

Error message

fail to write public key file: %w

What it means

generateCosignKeyPair writes the cosign public key bytes to publicKeyPath with mode 0644 after creating its directory. This error is returned when os.WriteFile fails (wrapped as 'fail to write public key file: %w').

Solutions

  1. Check the wrapped error and fix permissions or disk space on the public key path
  2. Ensure publicKeyPath is a file path in a writable directory
  3. Keep both keys on the same writable volume to avoid split-mount failures
  4. Pre-provision the public key directory with correct ownership in the image
Defensive patterns

Strategy: try-catch

Validate before calling

if fi, err := os.Stat(publicKeyPath); err == nil && fi.IsDir() {
	return fmt.Errorf("%s is a directory", publicKeyPath)
}
if err := syscall.Access(filepath.Dir(publicKeyPath), syscall.W_OK); err != nil {
	return fmt.Errorf("public key dir not writable: %w", err)
}

Try / catch

if err := generateCosignKeyPair(); err != nil {
	if strings.Contains(err.Error(), "fail to write public key file") {
		log.Fatalf("public key write failed (check disk space/permissions): %v", err)
	}
	log.Fatalf("cosign keypair init failed: %v", err)
}

Prevention

When it happens

Trigger: At init, writing the public key fails — parent directory not writable, disk full, publicKeyPath exists as a directory, or read-only filesystem.

Common situations: Same root causes as the private-key write error but on the public path: read-only rootfs, wrong ownership, disk exhaustion; often encountered right after fixing the private-key error when the two paths live on different mounts.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/0c964c246cfa3cfb. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/server/kbs/resource/resource.go:69

	keys, err := cosign.GenerateKeyPair(nil)
	if err != nil {
		return err
	}

	if err := os.MkdirAll(filepath.Dir(privateKeyPath), 0755); err != nil {
		return fmt.Errorf("fail to create private key directory: %w", err)
	}

	if err := os.MkdirAll(filepath.Dir(publicKeyPath), 0755); err != nil {
		return fmt.Errorf("fail to create public key directory: %w", err)
	}

	if err := os.WriteFile(privateKeyPath, keys.PrivateBytes, 0600); err != nil {
		return fmt.Errorf("fail to write private key file: %w", err)
	}

	if err := os.WriteFile(publicKeyPath, keys.PublicBytes, 0644); err != nil { //nolint:gosec // G306: Public keys are intentionally world-readable
		return fmt.Errorf("fail to write public key file: %w", err)
	}

	return nil
}

func GetResource(c *gin.Context) {
	path := c.Param("path")
	if path == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "resource path is empty"})
		return
	}

	authHeader := c.GetHeader("Authorization")
	if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
		c.JSON(http.StatusUnauthorized, kbsError.TokenNotFound())
		return
	}
	tokenStr := strings.TrimPrefix(authHeader, "Bearer ")

View on GitHub (pinned to 6e04ca5ff0)