kovidgoyal/kitty · error · ValueError

{spec} specified more than two easing functions

Error message

{spec} specified more than two easing functions

What it means

kitty animation specs allow at most two easing functions (one for each half of the animation). parse_func tracks slots m[0]/m[1]; a third easing function raises this ValueError.

Source

Thrown at kitty/options/utils.py:1739

                n = max(2, n)
            else:
                n = max(1, n)
        else:
            n = max(1, int(parts[0]))
        return cls(type='steps', jump_type=jump_type, num_steps=n)


def parse_animation(spec: str, interval: float = -1.0) -> tuple[float, EasingFunction, EasingFunction]:
    with suppress(Exception):
        interval = float(spec)
        return interval, EasingFunction(), EasingFunction()

    m = [EasingFunction(), EasingFunction()]

    def parse_func(func_name: str, params: str) -> None:
        idx = 1 if m[0] else 0
        if m[idx]:
            raise ValueError(f'{spec} specified more than two easing functions')
        if func_name == 'cubic-bezier':
            m[idx] = EasingFunction.cubic_bezier(params)
        elif func_name == 'linear':
            m[idx] = EasingFunction.linear(params)
        elif func_name == 'steps':
            m[idx] = EasingFunction.steps(params)
        else:
            raise KeyError(f'{func_name} is not a valid easing function')

    for match in re.finditer(r'([-+.0-9a-zA-Z]+)(?:\(([^)]*)\)){0,1}', spec):
        func_name, params = match.group(1, 2)
        if params:
            parse_func(func_name, params)
            continue
        with suppress(Exception):
            interval = float(func_name)
            continue
        if func_name == 'ease-in-out':

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Reduce to at most two easing functions in the spec
  2. Keep the form interval:ease1 (optionally ease2 for the second half)

Example fix

# before
cursor_blink_interval 0.5:ease-in ease-out ease-in-out
# after
cursor_blink_interval 0.5:ease-in ease-out
Defensive patterns

Strategy: validation

Validate before calling

import re
def max_two_easings(spec: str) -> bool:
    return len(re.findall(r'[-+.0-9a-zA-Z]+\([^)]*\)', spec)) <= 2 and len([t for t in re.findall(r'[-+.0-9a-zA-Z]+', spec) if t.isalpha()]) <= 2

Prevention

When it happens

Trigger: A spec like '0.5:ease-in ease-out linear(...)' containing three easing function names, or repeated named easings.

Common situations: Chaining multiple easings expecting them to compose, or leftover text parsed as an easing name.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/a2d2395bcb9efc7a. Report an issue: GitHub.