kovidgoyal/kitty · error

Password usage requested but KITTY_PUBLIC_KEY environment va

Error message

Password usage requested but KITTY_PUBLIC_KEY environment variable is not available

What it means

kitty @ (remote control CLI) was asked to use password-authenticated remote control, but the KITTY_PUBLIC_KEY environment variable is unset or empty. That variable is how kitty passes its public key to child processes so they can encrypt the password; without it no encrypted channel can be established.

Source

Thrown at tools/cmd/at/main.go:77

	for i, x := range args {
		ans[i] = escaped_string(x)
	}
	return ans
}

func set_payload_string_field(io_data *rc_io_data, field, data string) {
	payload_interface := reflect.ValueOf(&io_data.rc.Payload).Elem()
	struct_in_interface := reflect.New(payload_interface.Elem().Type()).Elem()
	struct_in_interface.Set(payload_interface.Elem()) // copies the payload to struct_in_interface
	struct_in_interface.FieldByName(field).SetString(data)
	payload_interface.Set(struct_in_interface) // copies struct_in_interface back to payload
}

func get_pubkey(encoded_key string) (encryption_version string, pubkey []byte, err error) {
	if encoded_key == "" {
		encoded_key = os.Getenv("KITTY_PUBLIC_KEY")
		if encoded_key == "" {
			err = fmt.Errorf("Password usage requested but KITTY_PUBLIC_KEY environment variable is not available")
			return
		}
	}
	encryption_version, encoded_key, found := strings.Cut(encoded_key, ":")
	if !found {
		err = fmt.Errorf("KITTY_PUBLIC_KEY environment variable does not have a : in it")
		return
	}
	if encryption_version != kitty.RC_ENCRYPTION_PROTOCOL_VERSION {
		err = fmt.Errorf("KITTY_PUBLIC_KEY has unknown version, if you are running on a remote system, update kitty on this system")
		return
	}
	pubkey = make([]byte, base85.DecodedLen(len(encoded_key)))
	n, err := base85.Decode(pubkey, []byte(encoded_key))
	if err == nil {
		pubkey = pubkey[:n]
	}
	return

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Run kitty @ from a process spawned by the kitty terminal itself (it exports KITTY_PUBLIC_KEY)
  2. If remote, echo/forward the value: on the local side read it and export it in the remote session, e.g. ssh host 'KITTY_PUBLIC_KEY="$KITTY_PUBLIC_KEY" kitty @ ls'
  3. Alternatively launch kitty with --execute and env passthrough, or use the remote control socket directly
  4. Update kitty on both ends so the variable is exported
Defensive patterns

Strategy: validation

Validate before calling

if os.Getenv("KITTY_PUBLIC_KEY") == "" {
    return errors.New("run inside kitty or forward KITTY_PUBLIC_KEY")
}

Type guard

func hasPublicKey() bool { return os.Getenv("KITTY_PUBLIC_KEY") != "" }

Try / catch

if _, _, err := get_pubkey(""); err != nil { /* fall back to --use-password=never or socket auth */ }

Prevention

When it happens

Trigger: Using --use-password with kitty @ (e.g. password required/always) when KITTY_PUBLIC_KEY was not inherited — typically because the command runs over ssh, from cron, or from a shell started before the variable existed.

Common situations: Running kitty @ on a remote host over ssh without forwarding the environment, invoking from systemd/launchd services, or shells whose startup files scrub the environment.

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/56b9a17da0a30964. Report an issue: GitHub.