lima-vm/lima · error

failed to read ssh public key %#q

Error message

failed to read ssh public key %#q: %w

What it means

readPublicKey wraps os.ReadFile failures for an SSH public key file (such as $LIMA_HOME/_config/user.pub) with the file path and the underlying OS error. The entry is still returned with an empty Content so callers can see which file failed.

Solutions

  1. Check permissions on the key file: it should be readable by the current user (chmod 600, chown to your user).
  2. Regenerate the key pair with limactl or ssh-keygen if user.pub is corrupted or root-owned.
  3. Investigate the wrapped OS error (path printed in the message) for the concrete cause (ENOENT, EACCES, etc.).

Example fix

// before
sudo limactl start   # created _config/user.pub owned by root
// after
sudo chown -R "$USER" ~/.lima/_config
chmod 600 ~/.lima/_config/user
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(pubKeyPath); err != nil { /* skip: key missing, let DefaultPubKeys create it */ }
if info, err := os.Stat(pubKeyPath); err == nil && !info.Mode().IsRegular() { /* not a normal file */ }

Type guard

func readable(f string) bool { h, err := os.Open(f); if err != nil { return false }; h.Close(); return true }

Try / catch

keys, err := sshutil.DefaultPubKeys(ctx)
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) { /* inspect pe.Path / pe.Err */ }
    return err
}

Prevention

When it happens

Trigger: DefaultPubKeys enumerates known public key files and calls readPublicKey; os.ReadFile fails with permission denied, an I/O error, or a race where the file disappears between existence check and read.

Common situations: _config/user.pub exists but is unreadable (wrong ownership/permissions, root-owned after sudo usage); file deleted concurrently; filesystem errors (full disk, broken symlink target).

Related errors


AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01). Data as JSON: /api/errors/b4d42d29cc4811e3. Report an issue: GitHub.

Appendix: source

Thrown at pkg/sshutil/sshutil.go:283

		return ""
	}
	return sftpServer
}

type PubKey struct {
	Filename string
	Content  string
}

func readPublicKey(f string) (PubKey, error) {
	entry := PubKey{
		Filename: f,
	}
	content, err := os.ReadFile(f)
	if err == nil {
		entry.Content = strings.TrimSpace(string(content))
	} else {
		err = fmt.Errorf("failed to read ssh public key %#q: %w", f, err)
	}
	return entry, err
}

// DefaultPubKeys returns the public key from $LIMA_HOME/_config/user.pub.
// The key will be created if it does not yet exist.
//
// When loadDotSSH is true, ~/.ssh/*.pub will be appended to make the VM accessible without specifying
// an identity explicitly.
func DefaultPubKeys(ctx context.Context, loadDotSSH bool) ([]PubKey, error) {
	// Read $LIMA_HOME/_config/user.pub
	configDir, err := dirnames.LimaConfigDir()
	if err != nil {
		return nil, err
	}
	_, err = os.Stat(filepath.Join(configDir, filenames.UserPrivateKey))
	if err != nil {
		if !errors.Is(err, os.ErrNotExist) {

View on GitHub (pinned to dd909d0973)