vercel/turborepo · critical

unhandled fkey number {n}

Error message

unhandled fkey number {n}

What it means

The TUI input encoder maps crossterm F-key codes to legacy terminal escape sequences, but the match arm only covers F1 through F12 — every other F(n) hits `_ => panic!("unhandled fkey number"). Terminals using the kitty keyboard protocol can deliver F13+ (up to F35), so an extended function key reaches the panic.

Source

Thrown at crates/turborepo-ui/src/tui/input.rs:346

                };
                buf.push_str(s);
            } else {
                // Higher numbered F-keys plus modified F-keys are encoded
                // using CSI instead of SS3.
                let intro = match n {
                    1 => "\x1b[11",
                    2 => "\x1b[12",
                    3 => "\x1b[13",
                    4 => "\x1b[14",
                    5 => "\x1b[15",
                    6 => "\x1b[17",
                    7 => "\x1b[18",
                    8 => "\x1b[19",
                    9 => "\x1b[20",
                    10 => "\x1b[21",
                    11 => "\x1b[23",
                    12 => "\x1b[24",
                    _ => panic!("unhandled fkey number {n}"),
                };
                let encoded_mods = encode_modifiers(mods);
                if encoded_mods == 0 {
                    // If no modifiers are held, don't send the modifier
                    // sequence, as the modifier encoding is a CSI-u extension.
                    buf.push_str(intro);
                    buf.push('~');
                } else {
                    buf.push_str(intro);
                    buf.push(';');
                    buf.push_str(&(1 + encoded_mods).to_string());
                    buf.push('~');
                }
            }
        }

        Null => (),
        CapsLock => (),

View on GitHub (pinned to f9245100cf)

Solutions

  1. Upgrade turbo — fixed versions map or safely drop extended F-keys
  2. Avoid pressing/macros bound to F13+ while the TUI is focused
  3. Disable the kitty keyboard protocol in the terminal settings as a workaround
  4. Report the key and terminal if it reproduces on the latest version

Example fix

// before
let intro = match n {
    1 => "\x1b[11",
    // ... 2..=12 handled ...
    _ => panic!("unhandled fkey number {n}"),
};
// after
if !(1..=12).contains(&n) {
    return None; // or encode via CSI-u for extended keys
}
let intro = match n { /* ... */ };
Defensive patterns

Strategy: validation

Validate before calling

// Guard before encoding extended F-keys
match key.code {
    crossterm::event::KeyCode::F(n) if !(1..=12).contains(&n) => {
        return None; // or encode via CSI-u instead of legacy sequences
    }
    _ => {}
}

Prevention

When it happens

Trigger: Encoding a KeyEvent with KeyCode::F(n) where n > 12: a keyboard/macro that emits F13–F35, a kitty-protocol terminal reporting extended keys, or a test/fuzzer synthesizing arbitrary key events.

Common situations: Power users with programmable keyboards mapping hotkeys to F13+; terminals with kitty keyboard protocol enabled; property tests generating the full KeyEvent space against the TUI.

Related errors


AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17). Data as JSON: /api/errors/a2226c3d0d14b82d. Report an issue: GitHub.