junegunn/fzf · error

invalid preview window option: ${token}

Error message

invalid preview window option: ${token}

What it means

Thrown by parsePreviewWindowImpl while tokenizing the --preview-window option. Each comma-separated token must match a known flag (hidden, nohidden, wrap, nowrap, cycle, border-*, down, up, left, right), a header spec (~N), a size (N or N%), or a scroll offset (+N, -N, +{n}, -/N); anything else lands in this default branch and is rejected after all regexes fail.

Source

Thrown at src/options.go:2419

		case "nofollow":
			opts.follow = false
		case "info":
			opts.info = true
		case "noinfo":
			opts.info = false
		default:
			if headerRegex.MatchString(token) {
				if opts.headerLines, err = atoi(token[1:]); err != nil {
					return err
				}
			} else if sizeRegex.MatchString(token) {
				if opts.size, err = parseSize(token, 99, "window size"); err != nil {
					return err
				}
			} else if offsetRegex.MatchString(token) {
				opts.scroll = token
			} else {
				return errors.New("invalid preview window option: " + token)
			}
		}
	}
	if len(alternative) > 0 {
		alternativeOpts := *opts
		opts.alternative = &alternativeOpts
		opts.alternative.hidden = false
		opts.alternative.alternative = nil
		err = parsePreviewWindowImpl(opts.alternative, alternative)
	}
	return err
}

func parseMargin(opt string, margin string) ([4]sizeSpec, error) {
	margins := strings.Split(margin, ",")
	checked := func(str string) (sizeSpec, error) {
		return parseSize(str, 49, opt)
	}

View on GitHub (pinned to bd4efa277b)

Solutions

  1. Replace removed tokens: 'tight' -> drop it or use 'border-none'; 'nohtight' likewise
  2. Check the man page (fzf --man) for the current token list and fix typos
  3. Split multi-token specs into repeated --preview-window flags to isolate the bad token

Example fix

# before (fzf <= 0.20 style)
fzf --preview-window right:50%:tight
# after
fzf --preview-window right:50%:border-none
Defensive patterns

Strategy: validation

Validate before calling

# bash: screen tokens against the known vocabulary
token_ok() {
  [[ "$1" =~ ^(hidden|nohidden|wrap|nowrap|cycle|nocycle|up|down|left|right|border|border-rounded|border-square|border-bold|border-block|border-thinblock|border-double|noborder|border-sharp|border-horizontal|border-vertical|border-top|border-bottom|border-left|border-right|follow|nofollow)$ ]] ||
  [[ "$1" =~ ^[0-9]+%?$ ]] || [[ "$1" =~ ^(\+\{-?[0-9]+|n\}|[+-][0-9]+|-?/[1-9][0-9]*)+$ ]] || [[ "$1" =~ ^~(0|[1-9][0-9]*)$ ]]
}
IFS=',' read -ra T <<< "$PW"; for t in "${T[@]}"; do token_ok "$t" || echo "bad token: $t" >&2; done

Prevention

When it happens

Trigger: `--preview-window 'tight'` (old fzf token removed), `--preview-window 'right:60:xx'`, `--preview-window 'border-rounded,'` trailing garbage, or a mistyped size like '5O%' (letter O).

Common situations: Carrying over 'tight'/'nohtight' from fzf <= 0.20 configs where tight was valid — it was later replaced by 'border-none' behavior; version upgrades breaking old alias scripts; unquoted specs where the shell splits or expands tokens.

Related errors


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