junegunn/fzf · error

not a valid number: ${str}

Error message

not a valid number: ${str}

What it means

Returned by LightRenderer.getBytesInternal (src/tui/light.go:387) when the input read loop accumulates more than maxInputBuffer (1 MiB, src/tui/light.go:28) bytes without an idle gap. The renderer reads terminal bytes in a tight non-blocking loop (assembling escape sequences and bracketed paste); the overflow check fires only when bytes keep arriving back-to-back, so fzf terminates immediately rather than allocating unbounded memory. The error is fatal: the renderer is closed and a Fatal event propagates.

Source

Thrown at src/options.go:835

}

func isDir(path string) bool {
	stat, err := os.Stat(path)
	return err == nil && stat.IsDir()
}

func atoi(str string) (int, error) {
	num, err := strconv.Atoi(str)
	if err != nil {
		return 0, errors.New("not a valid integer: " + str)
	}
	return num, nil
}

func atof(str string) (float64, error) {
	num, err := strconv.ParseFloat(str, 64)
	if err != nil {
		return 0, errors.New("not a valid number: " + str)
	}
	return num, nil
}

func splitNth(str string) ([]Range, error) {
	if match, _ := regexp.MatchString("^[0-9,-.]+$", str); !match {
		return nil, errors.New("invalid format: " + str)
	}

	tokens := strings.Split(str, ",")
	ranges := make([]Range, len(tokens))
	for idx, s := range tokens {
		r, ok := ParseRange(&s)
		if !ok {
			return nil, errors.New("invalid format: " + str)
		}
		ranges[idx] = r
	}

View on GitHub (pinned to bd4efa277b)

Solutions

  1. Feed large data to fzf on stdin (the candidate list) instead of pasting it into the query line: `huge_file | fzf` or `fzf < query.txt`.
  2. Find and stop the process flooding the tty: check for runaway writers to the terminal (`ps aux | grep -E 'cat|echo'`, multiplexer panes) and re-run fzf in a clean terminal.
  3. Keep pastes under ~1 MiB or disable bracketed paste in your terminal emulator if it wraps giant pastes into one uninterrupted escape sequence.
  4. If you drive fzf programmatically via its tty, write input in chunks with small pauses (>= escPollInterval-scale gaps) so the read loop can flush the buffer between bursts.
  5. If a specific large paste legitimately must be searched, put it in a file and use fzf's file input rather than the interactive query.

Example fix

# before (pasting a 2 MB block into the query line -> fatal overflow)
#   fzf
<paste of huge.txt>

# after (data on stdin, query stays tiny)
cat huge.txt | fzf
# or preload the initial query from a file within size limits:
cat huge.txt | fzf --query="$(head -c 1000 query.txt)"
Defensive patterns

Strategy: validation

Validate before calling

// Shell wrapper: gate pastes/programmatic query injection by size
max_query=100000 # well under fzf's 1 MiB input buffer
if [ "$(wc -c < query.txt)" -gt "$max_query" ]; then
    echo "query too large for tty input; use stdin instead" >&2
    exit 1
fi
cat items.txt | fzf --query="$(cat query.txt)"

# Go driver writing to fzf's tty: chunk with gaps so fzf's read loop flushes
func writeChunked(w io.Writer, data []byte) error {
    for len(data) > 0 {
        n := len(data)
        if n > 64*1024 {
            n = 64 * 1024
        }
        if _, err := w.Write(data[:n]); err != nil {
            return err
        }
        data = data[n:]
        time.Sleep(5 * time.Millisecond) // idle gap lets fzf finish one buffer
    }
    return nil
}

Type guard

func isInputBufferOverflow(stderr string) bool {
    return strings.Contains(stderr, "input buffer overflow")
}

Try / catch

// fzf exits fatally on this error; the only 'catch' is at the process level:
out, err := cmd.CombinedOutput()
if err != nil && strings.Contains(string(out), "input buffer overflow") {
    // relaunch with the large payload delivered via stdin instead of the tty
}

Prevention

When it happens

Trigger: A single burst of uninterrupted terminal input exceeding 1 MiB: pasting (or having a tool write) an extremely large block into the fzf TTY, especially with bracketed-paste escape wrappers; a misbehaving program or script (`cat hugefile > $(tty)`, a runaway loop writing to the terminal, a tmux/screen pane flooding output) feeding continuous bytes so the loop never sees an idle poll; terminal emulators replaying huge scrollback or macros. Normal typing and ordinary pastes never reach 1 MiB in one gapless burst.

Common situations: Pasting an entire minified JS bundle or a huge JSON file into fzf's query line instead of feeding it on stdin; shell scripts that `echo`/`printf` megabytes into the tty where fzf is running; a key-repeating macro or stuck key bridged by a terminal multiplexer; CI harnesses driving fzf's tty with oversized synthetic input; latency spikes on slow links that batch >1 MiB of input into one readable chunk.

Related errors


AI-assisted analysis of junegunn/fzf@bd4efa277b (2026-08-15). Data as JSON: /api/errors/c83ffdbd81ee3843. Report an issue: GitHub.