kovidgoyal/kitty · error
invalid file descriptor: %d
Error message
invalid file descriptor: %d
What it means
When --password fd:N is used, Go's os.NewFile is called with the given integer. If the runtime cannot turn that number into a usable *os.File (it returns nil), the kitten reports 'invalid file descriptor: N'. In practice this branch is rarely hit because most integers yield a non-nil File; read failures surface as error 303 instead.
Source
Thrown at kittens/clipboard/main.go:42
return run_set_loop(opts, args)
}
func clipboard_main(cmd *cli.Command, opts *Options, args []string) (rc int, err error) {
if opts.Password != "" {
if opts.HumanName == "" {
return 1, fmt.Errorf("must specify --human-name when using a password")
}
ptype, val, found := strings.Cut(opts.Password, ":")
if !found {
return 1, fmt.Errorf("invalid password: %#v no password type specified", opts.Password)
}
switch ptype {
case "text":
opts.Password = val
case "fd":
if fd, err := strconv.Atoi(val); err == nil {
if f := os.NewFile(uintptr(fd), "password-fd"); f == nil {
return 1, fmt.Errorf("invalid file descriptor: %d", fd)
} else {
data, err := io.ReadAll(f)
f.Close()
if err != nil {
return 1, fmt.Errorf("failed to read from file descriptor: %d with error: %w", fd, err)
}
opts.Password = strings.TrimRightFunc(string(data), unicode.IsSpace)
}
} else {
return 1, fmt.Errorf("not a valid file descriptor number: %#v", val)
}
case "file":
if data, err := os.ReadFile(val); err == nil {
opts.Password = strings.TrimRightFunc(string(data), unicode.IsSpace)
} else {
return 1, fmt.Errorf("failed to read from file: %#v with error: %w", val, err)
}View on GitHub (pinned to 6d5d0c4406)
Solutions
- Ensure the file descriptor is actually open in the kitten process — open it in the parent shell: `kitten ... --password fd:3 3< password.txt`
- Prefer the file: form (`--password file:/path/to/pw`) which avoids fd bookkeeping entirely
- Double-check the fd number matches the one you redirected
Example fix
# before kitten clipboard get --human-name me --password fd:7 # fd 7 not open # after kitten clipboard get --human-name me --password fd:3 3< ~/.clipboard-pw
Defensive patterns
Strategy: validation
Validate before calling
# verify the fd is open and readable before exec'ing kitten
if ! { : <&3; } 2>/dev/null; then echo "fd 3 not readable"; exit 2; fi
kitten clipboard get --human-name me --password fd:3 ... Prevention
- Open the fd in the parent shell with 3< file
- Prefer --password file: to avoid fd arithmetic
- Test fd readability with `: <&N` before use
When it happens
Trigger: Passing `--password fd:N` where N is a number that cannot be wrapped into a file handle by os.NewFile at all (nil return), typically a degenerate value on the current platform.
Common situations: Typos in the fd number; platforms/runtime versions where os.NewFile returns nil for out-of-range descriptors; passing an fd that was never opened by the parent process (which usually fails later at read time instead).
Related errors
- must specify --human-name when using a password
- failed to read from file descriptor: %d with error: %w
- not a valid file descriptor number: %#v
- Too much piped data
- Failed to read from STDIN pipe with error: %w
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/2bdbfe71f22adb3e.
Report an issue: GitHub.