{"record":{"id":"a2226c3d0d14b82d","repo":"vercel/turborepo","slug":"unhandled-fkey-number-n","errorCode":null,"errorMessage":"unhandled fkey number {n}","messagePattern":"unhandled fkey number (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/turborepo-ui/src/tui/input.rs","lineNumber":346,"sourceCode":"                };\n                buf.push_str(s);\n            } else {\n                // Higher numbered F-keys plus modified F-keys are encoded\n                // using CSI instead of SS3.\n                let intro = match n {\n                    1 => \"\\x1b[11\",\n                    2 => \"\\x1b[12\",\n                    3 => \"\\x1b[13\",\n                    4 => \"\\x1b[14\",\n                    5 => \"\\x1b[15\",\n                    6 => \"\\x1b[17\",\n                    7 => \"\\x1b[18\",\n                    8 => \"\\x1b[19\",\n                    9 => \"\\x1b[20\",\n                    10 => \"\\x1b[21\",\n                    11 => \"\\x1b[23\",\n                    12 => \"\\x1b[24\",\n                    _ => panic!(\"unhandled fkey number {n}\"),\n                };\n                let encoded_mods = encode_modifiers(mods);\n                if encoded_mods == 0 {\n                    // If no modifiers are held, don't send the modifier\n                    // sequence, as the modifier encoding is a CSI-u extension.\n                    buf.push_str(intro);\n                    buf.push('~');\n                } else {\n                    buf.push_str(intro);\n                    buf.push(';');\n                    buf.push_str(&(1 + encoded_mods).to_string());\n                    buf.push('~');\n                }\n            }\n        }\n\n        Null => (),\n        CapsLock => (),","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-ui/src/tui/input.rs#L328-L364","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Upgrade turbo — fixed versions map or safely drop extended F-keys","Avoid pressing/macros bound to F13+ while the TUI is focused","Disable the kitty keyboard protocol in the terminal settings as a workaround","Report the key and terminal if it reproduces on the latest version"],"exampleFix":"// before\nlet intro = match n {\n    1 => \"\\x1b[11\",\n    // ... 2..=12 handled ...\n    _ => panic!(\"unhandled fkey number {n}\"),\n};\n// after\nif !(1..=12).contains(&n) {\n    return None; // or encode via CSI-u for extended keys\n}\nlet intro = match n { /* ... */ };","handlingStrategy":"validation","validationCode":"// Guard before encoding extended F-keys\nmatch key.code {\n    crossterm::event::KeyCode::F(n) if !(1..=12).contains(&n) => {\n        return None; // or encode via CSI-u instead of legacy sequences\n    }\n    _ => {}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In downstream TUIs, filter or clamp F-key codes above F12 before legacy encoding","Disable the kitty keyboard protocol if your terminal emits extended F-keys turbo cannot encode","Fuzz key-event encoders with the full KeyCode range to catch unhandled match arms"],"tags":["tui","keyboard","f-keys","panic","terminal"],"backgroundTag":"unsupported-key-encoding","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}