junegunn/fzf · error

index should be the last criterion

Error message

index should be the last criterion

What it means

Within parseTiebreak's check() closure: 'index' means input order, which is only meaningful as the final tiebreaker. Once hasIndex is true, any further criterion token triggers this error, telling you index must come last in the --tiebreak list.

Source

Thrown at src/options.go:1362

		return str, []criterion{byScore, byLength}, nil
	}
	return str, nil, errors.New("invalid scoring scheme: " + str + " (expected: default|path|history)")
}

func parseTiebreak(str string) ([]criterion, error) {
	criteria := []criterion{byScore}
	hasIndex := false
	hasChunk := false
	hasLength := false
	hasBegin := false
	hasEnd := false
	hasPathname := false
	check := func(notExpected *bool, name string) error {
		if *notExpected {
			return errors.New("duplicate sort criteria: " + name)
		}
		if hasIndex {
			return errors.New("index should be the last criterion")
		}
		*notExpected = true
		return nil
	}
	for _, str := range strings.Split(strings.ToLower(str), ",") {
		switch str {
		case "index":
			if err := check(&hasIndex, "index"); err != nil {
				return nil, err
			}
		case "chunk":
			if err := check(&hasChunk, "chunk"); err != nil {
				return nil, err
			}
			criteria = append(criteria, byChunk)
		case "pathname":
			if err := check(&hasPathname, "pathname"); err != nil {
				return nil, err

View on GitHub (pinned to bd4efa277b)

Solutions

  1. Move index to the end: --tiebreak length,begin,index
  2. Drop trailing criteria after index, or drop index if earlier ordering matters more

Example fix

# before
fzf --tiebreak index,length
# after
fzf --tiebreak length,index
Defensive patterns

Strategy: validation

Validate before calling

TB='length,index'
IFS=',' read -ra C <<< "$TB"
LAST="${C[-1]}"
[[ "$LAST" == index ]] || grep -qxF index <(printf '%s\n' "${C[@]}") && { echo 'index must be last' >&2; exit 1; }
fzf --tiebreak "$TB"

Prevention

When it happens

Trigger: --tiebreak index,length (index first, then more); --tiebreak begin,index,end (end appears after index). Both add criteria after index was consumed.

Common situations: Users treating the list as unordered; migrating from scripts that appended 'index' early; editing an existing comma list by inserting a criterion before the trailing index.

Related errors


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