{"record":{"id":"64bcaaab6397f521","repo":"kovidgoyal/kitty","slug":"failed-to-read-from-file-descriptor-d-with-error","errorCode":null,"errorMessage":"failed to read from file descriptor: %d with error: %w","messagePattern":"failed to read from file descriptor: (.+?) with error: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kittens/clipboard/main.go","lineNumber":47,"sourceCode":"\t\tif opts.HumanName == \"\" {\n\t\t\treturn 1, fmt.Errorf(\"must specify --human-name when using a password\")\n\t\t}\n\t\tptype, val, found := strings.Cut(opts.Password, \":\")\n\t\tif !found {\n\t\t\treturn 1, fmt.Errorf(\"invalid password: %#v no password type specified\", opts.Password)\n\t\t}\n\t\tswitch ptype {\n\t\tcase \"text\":\n\t\t\topts.Password = val\n\t\tcase \"fd\":\n\t\t\tif fd, err := strconv.Atoi(val); err == nil {\n\t\t\t\tif f := os.NewFile(uintptr(fd), \"password-fd\"); f == nil {\n\t\t\t\t\treturn 1, fmt.Errorf(\"invalid file descriptor: %d\", fd)\n\t\t\t\t} else {\n\t\t\t\t\tdata, err := io.ReadAll(f)\n\t\t\t\t\tf.Close()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn 1, fmt.Errorf(\"failed to read from file descriptor: %d with error: %w\", fd, err)\n\t\t\t\t\t}\n\t\t\t\t\topts.Password = strings.TrimRightFunc(string(data), unicode.IsSpace)\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\treturn 1, fmt.Errorf(\"not a valid file descriptor number: %#v\", val)\n\t\t\t}\n\t\tcase \"file\":\n\t\t\tif data, err := os.ReadFile(val); err == nil {\n\t\t\t\topts.Password = strings.TrimRightFunc(string(data), unicode.IsSpace)\n\t\t\t} else {\n\t\t\t\treturn 1, fmt.Errorf(\"failed to read from file: %#v with error: %w\", val, err)\n\t\t\t}\n\t\t}\n\t}\n\tif len(args) > 0 {\n\t\treturn 0, run_mime_loop(opts, args)\n\t}","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kittens/clipboard/main.go#L29-L65","documentation":"After successfully wrapping --password fd:N into a *os.File, the kitten reads it to EOF. If the read itself fails (I/O error, closed pipe, bad fd at read time), the error is wrapped with the offending descriptor number and the underlying cause.","triggerScenarios":"`--password fd:N` where the descriptor exists but reading fails: the write end of a pipe was closed, the fd refers to a write-only or closed handle, or the underlying file hit an I/O error during io.ReadAll.","commonSituations":"Opening a fd write-only and passing it for reading; the producer process exiting before the kitten reads; passing a socket or device fd that errors on read; fd inheritance issues under systemd or container runtimes that close inherited fds.","solutions":["Verify the fd is readable: `ls -l /proc/self/fd/N` in the same process context, or test with `cat <&N`","Keep the writer alive until the kitten has read the password, or use a regular file: `--password file:pw.txt`","Check the underlying error message (%w) to identify the true errno (EBADF, EPIPE, etc.)"],"exampleFix":"# before\nkitten clipboard get --human-name me --password fd:3  # fd 3 is write-only\n# after\nkitten clipboard get --human-name me --password file:/etc/myapp/clipboard-pw","handlingStrategy":"fallback","validationCode":"# fall back to file: if reading the fd may fail\n[ -r \"$PWFILE\" ] && PWARG=\"file:$PWFILE\" || PWARG=\"fd:3\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the writer process alive until the read completes","Open fds read-only for password delivery","Prefer regular files over pipes for password delivery"],"tags":["kitty","clipboard","file-descriptor","io-read-failure"],"backgroundTag":"file-descriptor-read-failure","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}