OpenNHP/opennhp · critical

fail to create private key directory

Error message

fail to create private key directory: %w

What it means

generateCosignKeyPair creates the cosign key pair at init time and prepares the directories for the private and public key files. This error is returned when os.MkdirAll for the private key's parent directory fails (wrapped as 'fail to create private key directory: %w').

Solutions

  1. Check the wrapped error for EACCES/EROFS and fix filesystem permissions or mount
  2. Verify privateKeyPath (private key dir env/config) points to a writable location
  3. Run the daemon as a user with write access to the target directory
  4. Pre-create the directory in the deployment image and give it proper ownership

Example fix

// before
if err := os.MkdirAll(filepath.Dir(privateKeyPath), 0755); err != nil {
	return fmt.Errorf("fail to create private key directory: %w", err)
}
// after (configurable, validated path)
keyDir := os.Getenv("KBS_KEY_DIR")
if keyDir == "" {
	keyDir = defaultKeyDir
}
if err := os.MkdirAll(keyDir, 0700); err != nil {
	return fmt.Errorf("fail to create private key directory %s: %w", keyDir, err)
}
Defensive patterns

Strategy: validation

Validate before calling

keyDir := filepath.Dir(privateKeyPath)
if fi, err := os.Stat(keyDir); err == nil && !fi.IsDir() {
	return fmt.Errorf("%s exists and is not a directory", keyDir)
}
if err := os.MkdirAll(keyDir, 0755); err != nil {
	return err
}
if f, err := os.CreateTemp(keyDir, ".wtest"); err != nil {
	return fmt.Errorf("key dir not writable: %w", err)
} else {
	f.Close(); os.Remove(f.Name())
}

Try / catch

if err := generateCosignKeyPair(); err != nil {
	if strings.Contains(err.Error(), "fail to create private key directory") {
		log.Fatalf("cannot create key dir, check permissions/read-only fs: %v", err)
	}
	log.Fatalf("cosign keypair init failed: %v", err)
}

Prevention

When it happens

Trigger: At package init, filepath.Dir(privateKeyPath) cannot be created — parent path is an existing file, permission denied, or a read-only filesystem.

Common situations: Deploying nhp-server with a read-only rootfs; privateKeyPath configured under a directory owned by another user; running the daemon without the required user in Docker; a typo making the dir path collide with an existing file.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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

Appendix: source

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

	if err != nil {
		panic(err)
	}
}

func generateCosignKeyPair(privateKeyPath, publicKeyPath string) error {
	if _, err := os.Stat(privateKeyPath); err == nil {
		if _, err := os.Stat(publicKeyPath); err == nil {
			return nil
		}
	}

	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) {

View on GitHub (pinned to 6e04ca5ff0)