kovidgoyal/kitty · error

KITTY_PUBLIC_KEY env var not set, cannot transmit password s

Error message

KITTY_PUBLIC_KEY env var not set, cannot transmit password securely

What it means

The transfer kitten encrypts the password/file data with the recipient's public key before sending it over the socket. It reads the recipient's base64 public key from the KITTY_PUBLIC_KEY environment variable; when that variable is empty or unset, encryption cannot be performed and encode_bypass returns this error instead of transmitting the secret in plaintext.

Source

Thrown at kittens/transfer/utils.go:50

		return utils.Expanduser("~")
	}
	return global_home
}

func encode_bypass(request_id string, bypass string) (string, error) {
	q := request_id + ";" + bypass
	if pkey_encoded := os.Getenv("KITTY_PUBLIC_KEY"); pkey_encoded != "" {
		encryption_protocol, pubkey, err := crypto.DecodePublicKey(pkey_encoded)
		if err != nil {
			return "", err
		}
		encrypted, err := crypto.Encrypt_data(utils.UnsafeStringToBytes(q), pubkey, encryption_protocol)
		if err != nil {
			return "", err
		}
		return fmt.Sprintf("kitty-1:%s", utils.UnsafeBytesToString(encrypted)), nil
	}
	return "", fmt.Errorf("KITTY_PUBLIC_KEY env var not set, cannot transmit password securely")
}

func abspath(path string, use_home ...bool) string {
	if filepath.IsAbs(path) {
		return path
	}
	var base string
	if len(use_home) > 0 && use_home[0] {
		base = home_path()
	} else {
		base = cwd_path()
	}
	return filepath.Join(base, path)
}

func expand_home(path string) string {
	if strings.HasPrefix(path, "~"+string(os.PathSeparator)) {
		path = strings.TrimLeft(path[2:], string(os.PathSeparator))

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Ensure the transfer kitten is launched from within kitty itself, which sets KITTY_PUBLIC_KEY on the child process
  2. Upgrade both ends (sender and receiver) to matching kitty versions so public key exchange happens
  3. If invoking manually, export a valid base64 public key: KITTY_PUBLIC_KEY=$(kitty +kitten query-public-key) before running the kitten
  4. Avoid sending passwords when the key is unavailable: pass an empty password and authenticate out-of-band

Example fix

// before
q := os.Getenv("KITTY_PUBLIC_KEY")
encrypted, err := crypto.Encrypt_data([]byte(pw), pubkey, proto)

// after
pubkey := os.Getenv("KITTY_PUBLIC_KEY")
if pubkey == "" {
    log.Fatal("run this kitten from inside kitty so KITTY_PUBLIC_KEY is set")
}
Defensive patterns

Strategy: validation

Validate before calling

pubkey := os.Getenv("KITTY_PUBLIC_KEY")
if pubkey == "" {
    return errors.New("KITTY_PUBLIC_KEY missing; run inside kitty or export the recipient public key")
}

Try / catch

if _, err := encode_bypass(pw); err != nil {
    if strings.Contains(err.Error(), "KITTY_PUBLIC_KEY") {
        // fall back to manual password entry / abort transfer
    }
}

Prevention

When it happens

Trigger: Calling kittens/transfer code paths that send a password or encrypted payload (receive_loop, initialize) in a process where KITTY_PUBLIC_KEY is not in the environment — e.g. running the transfer kitten manually, spawning it through a wrapper that strips env vars, or a kitten version mismatch where the parent never exported the key.

Common situations: Running the transfer kitten outside a normal kitty window session; SSH/tmux environments that drop kitty-specific env vars; stale kitty versions where the remote side doesn't advertise its public key; scripts invoking the kitten binary directly for testing.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/b3160d22b3fc99dd. Report an issue: GitHub.