{"record":{"id":"954abc32cc362eab","repo":"junegunn/fzf","slug":"bind-action-not-specified-keys","errorCode":null,"errorMessage":"bind action not specified: ${keys}","messagePattern":"bind action not specified: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/options.go","lineNumber":2057,"sourceCode":"\t\t\t\tkey = tui.Key(',')\n\t\t\t} else if len(keyName) == 1 && keyName[0] == escapedPlus {\n\t\t\t\tkey = tui.Key('+')\n\t\t\t} else {\n\t\t\t\tkeys, _, err := parseKeyChords(keyName, \"key name required\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tkey = firstKey(keys)\n\t\t\t}\n\t\t\tkeymap[key], err = parseActionList(pair[1], origPairStr[len(pair[0])+1:], keymap[key], key.Printable())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tkeys = keys[:0]\n\t}\n\tif len(keys) > 0 {\n\t\treturn errors.New(\"bind action not specified: \" + strings.Join(keys, \", \"))\n\t}\n\treturn nil\n}\n\nfunc isExecuteAction(str string) actionType {\n\tmasked := maskActionContents(\":\" + str)[1:]\n\tif masked == str {\n\t\t// Not masked\n\t\treturn actIgnore\n\t}\n\n\tprefix := actionNameRegexp.FindString(str)\n\tswitch prefix {\n\tcase \"become\":\n\t\treturn actBecome\n\tcase \"reload\":\n\t\treturn actReload\n\tcase \"reload-sync\":","sourceCodeStart":2039,"sourceCodeEnd":2075,"githubUrl":"https://github.com/junegunn/fzf/blob/bd4efa277b49ef34ca4025bff9b1a288e1980eff/src/options.go#L2039-L2075","documentation":"Thrown by parseKeymap at the end of --bind parsing. fzf allows multi-key binds ('a,b:accept'), accumulating pending key names until an action appears. If the input ends while keys are still pending (len(keys) > 0), those keys have no action bound and the option is rejected.","triggerScenarios":"`--bind 'ctrl-a'` (single key, no colon/action), `--bind 'a,b'` (multi-key chord with no action), or a trailing fragment like `--bind 'ctrl-a:accept,a,b'` where the last chord has no action. Also the leading-comma case: ',ctrl-a:accept' leaves an empty pending key.","commonSituations":"Splitting a long bind list across shell lines and dropping the ':action' part of the last entry; refactoring bind strings and forgetting to close the final chord; truncated variables.","solutions":["Make every key or key group in the --bind list is followed by ':action'","Remove dangling trailing fragments like ',a,b' that have no action","Split complex binds into multiple --bind flags so each is easy to validate"],"exampleFix":"# before\nfzf --bind 'ctrl-a:accept,a,b'\n# after\nfzf --bind 'ctrl-a:accept' --bind 'a,b:accept'","handlingStrategy":"validation","validationCode":"# bash: every comma-separated bind pair must contain ':action'\nbinds_ok() {\n  IFS=',' read -ra p <<< \"$1\"\n  for x in \"${p[@]}\"; do [[ \"$x\" == *:* ]] || return 1; done\n}\nbinds_ok \"$BINDS\" || { echo \"each --bind entry needs key:action\" >&2; exit 1; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One --bind flag per binding keeps strings short and self-checking","When using multi-key chords, always terminate the group with ':action'"],"tags":["fzf","go","cli","keybinding","parsing"],"backgroundTag":null,"analyzedSha":"bd4efa277b49ef34ca4025bff9b1a288e1980eff","analyzedAt":"2026-08-15T06:11:46.983Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}