{"record":{"id":"d9ec92847cd259ec","repo":"junegunn/fzf","slug":"failed-to-read-s","errorCode":null,"errorMessage":"failed to read %s","messagePattern":"failed to read (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/tui/light.go","lineNumber":352,"sourceCode":"\tenv := os.Getenv(name)\n\tif len(env) == 0 {\n\t\treturn defaultValue\n\t}\n\treturn atoi(env, defaultValue)\n}\n\nfunc (r *LightRenderer) getBytes(cancellable bool) ([]byte, getCharResult, error) {\n\treturn r.getBytesInternal(cancellable, r.buffer, false)\n}\n\nfunc (r *LightRenderer) getBytesInternal(cancellable bool, buffer []byte, nonblock bool) ([]byte, getCharResult, error) {\n\tc, result := r.getch(cancellable, nonblock)\n\tif result == getCharCancelled {\n\t\treturn buffer, getCharCancelled, nil\n\t}\n\tif !nonblock && !result.ok() {\n\t\tr.Close()\n\t\treturn nil, getCharError, errors.New(\"failed to read \" + DefaultTtyDevice)\n\t}\n\n\tretries := 0\n\tif c == Esc.Int() || nonblock {\n\t\tretries = r.escDelay / escPollInterval\n\t}\n\t// A non-blocking read that found nothing has no byte to record. Recording\n\t// one would put a NUL in the middle of a reply still being assembled.\n\tif result.ok() {\n\t\tbuffer = append(buffer, byte(c))\n\t}\n\n\tpc := c\n\tfor {\n\t\tc, result = r.getch(false, true)\n\t\tif !result.ok() {\n\t\t\tif retries > 0 {\n\t\t\t\tretries--","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/junegunn/fzf/blob/bd4efa277b49ef34ca4025bff9b1a288e1980eff/src/tui/light.go#L334-L370","documentation":"The light TUI renderer could not read a character from the terminal: r.getch returned a non-OK result that is not cancellation, so the renderer closes itself and reports 'failed to read /dev/tty' (DefaultTtyDevice). It usually means stdin's TTY went away or a non-blocking read hit a hard error.","triggerScenarios":"fzf's light renderer reads input from the TTY and the read fails: the terminal was closed while fzf was running, the pty was torn down (session leader exited), or a raw-mode read on /dev/tty returned an error (EBADF/EIO).","commonSituations":"Running fzf under ssh and the connection drops; terminal multiplexers killing the pane; CI harnesses or test runners that provide no real TTY then close stdin; nested programs stealing then closing the tty.","solutions":["Reproduce with a real terminal; if this happens in CI/tests, provide a pty (e.g. 'script -qc \"fzf\" /dev/null')","If the terminal genuinely died, this error is expected — just let fzf exit non-zero","For scripting without interaction, drive fzf via its --filter mode instead of the interactive renderer"],"exampleFix":"# before\nfzf < /dev/null   # no tty for interaction\n# after\necho -e 'a\\nb' | fzf --filter 'a'","handlingStrategy":"fallback","validationCode":"# offer a non-interactive path when no usable tty exists\nif [ ! -t 0 ] || [ ! -t 1 ]; then\n  printf '%s\\n' \"${ITEMS[@]}\" | fzf --filter \"$QUERY\"\nelse\n  printf '%s\\n' \"${ITEMS[@]}\" | fzf --query \"$QUERY\"\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check [ -t 0 ] && [ -t 1 ] before launching interactive fzf","Use --filter in scripts, cron, and CI where terminals are absent"],"tags":["fzf","tui","terminal","io"],"backgroundTag":null,"analyzedSha":"bd4efa277b49ef34ca4025bff9b1a288e1980eff","analyzedAt":"2026-08-15T06:11:46.983Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}