kubernetes/kops · error

error reading SSH key file %q: %v

Error message

error reading SSH key file %q: %v

What it means

During `kops create cluster`, if --ssh-public-key was provided, loadSSHPublicKeys(sshPublicKey) is called to read and parse the key file; a read failure is wrapped as 'error reading SSH key file'. It means the file could not be opened or read from disk.

Source

Thrown at cmd/kops/create_cluster.go:222

		RunE: func(cmd *cobra.Command, args []string) error {
			var err error

			if cmd.Flag("associate-public-ip").Changed {
				options.AssociatePublicIP = &associatePublicIP
			}

			if cmd.Flag("encrypt-etcd-storage").Changed {
				options.EncryptEtcdStorage = &encryptEtcdStorage
			}

			if err := checkProjectFlag(cmd.Flag("project").Changed, options.Project); err != nil {
				return err
			}

			if sshPublicKey != "" {
				options.SSHPublicKeys, err = loadSSHPublicKeys(sshPublicKey)
				if err != nil {
					return fmt.Errorf("error reading SSH key file %q: %v", sshPublicKey, err)
				}
			}

			return RunCreateCluster(cmd.Context(), f, out, options)
		},
	}

	cmd.Flags().BoolVarP(&options.Yes, "yes", "y", options.Yes, "Specify --yes to immediately create the cluster")
	cmd.Flags().Var(&options.Target, "target", fmt.Sprintf("Valid targets: %q, %q. Set this flag to %q if you want kOps to generate terraform", cloudup.TargetDirect, cloudup.TargetTerraform, cloudup.TargetTerraform))
	cmd.RegisterFlagCompletionFunc("target", completeCreateClusterTarget(options))

	// Configuration / state location
	if featureflag.EnableSeparateConfigBase.Enabled() {
		cmd.Flags().StringVar(&options.ConfigBase, "config-base", options.ConfigBase, "A cluster-readable location where we mirror configuration information, separate from the state store.  Allows for a state store that is not accessible from the cluster.")
		cmd.RegisterFlagCompletionFunc("config-base", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
			// TODO complete vfs paths
			return nil, cobra.ShellCompDirectiveNoFileComp
		})

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Verify the path passed to --ssh-public-key exists and points to a .pub public key file
  2. Check file permissions (must be readable by the current user)
  3. Use an absolute path in CI/containers where the working directory or HOME differs
  4. Pass an empty value or omit the flag to skip SSH key loading

Example fix

// before
kops create cluster --ssh-public-key ~/.ssh/id_rsa ...
// after
kops create cluster --ssh-public-key ~/.ssh/id_rsa.pub ...
Defensive patterns

Strategy: validation

Validate before calling

func validateSSHPublicKey(path string) error {
	if path == "" { return nil }
	fi, err := os.Stat(path)
	if err != nil { return fmt.Errorf("ssh key not found: %w", err) }
	if fi.IsDir() { return fmt.Errorf("%s is a directory", path) }
	data, err := os.ReadFile(path)
	if err != nil { return err }
	if !strings.HasPrefix(string(data), "ssh-") {
		return fmt.Errorf("%s does not look like a public key", path)
	}
	return nil
}

Prevention

When it happens

Trigger: Passing --ssh-public-key with a path that does not exist, is a directory, or lacks read permissions when building CreateClusterOptions before RunCreateCluster is invoked.

Common situations: Typo in the key path; using ~/.ssh/id_rsa (private key) instead of the .pub file; running in CI where the key file wasn't mounted; wrong HOME so ~ expansion fails.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/19532bc1ba93b210. Report an issue: GitHub.