{"record":{"id":"8563a567249f8596","repo":"zed-industries/zed","slug":"cannot-remove-a-keybinding-that-does-not-exist","errorCode":null,"errorMessage":"Cannot remove a keybinding that does not exist","messagePattern":"Cannot remove a keybinding that does not exist","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/keymap_editor/src/keymap_editor.rs","lineNumber":3697,"sourceCode":"    .context(\"Failed to write keymap file\")?;\n\n    telemetry::event!(\n        \"Keybinding Updated\",\n        new_keybinding = new_keybinding,\n        removed_keybinding = removed_keybinding,\n        source = source\n    );\n    Ok(())\n}\n\nasync fn remove_keybinding(\n    existing: ProcessedBinding,\n    fs: &Arc<dyn Fs>,\n    keyboard_mapper: &dyn PlatformKeyboardMapper,\n    deprecated_aliases: &HashMap<&'static str, &'static str>,\n) -> anyhow::Result<()> {\n    let Some(keystrokes) = existing.keystrokes() else {\n        anyhow::bail!(\"Cannot remove a keybinding that does not exist\");\n    };\n    let keymap_contents = settings::KeymapFile::load_keymap_file(fs)\n        .await\n        .context(\"Failed to load keymap file\")?;\n    let tab_size = infer_json_indent_size(&keymap_contents);\n\n    let operation = settings::KeybindUpdateOperation::Remove {\n        target: settings::KeybindUpdateTarget {\n            context: existing.context().and_then(KeybindContextString::local_str),\n            keystrokes,\n            action_name: existing.action().name,\n            action_arguments: existing\n                .action()\n                .arguments\n                .as_ref()\n                .map(|arguments| arguments.text.as_ref()),\n        },\n        target_keybind_source: existing.keybind_source().unwrap_or(KeybindSource::User),","sourceCodeStart":3679,"sourceCodeEnd":3715,"githubUrl":"https://github.com/zed-industries/zed/blob/9d272b036335401f339d024ea94968fd51016c40/crates/keymap_editor/src/keymap_editor.rs#L3679-L3715","documentation":"remove_keybinding walks the user keymap file to delete the entry matching a ProcessedBinding; the removal machinery matches on keystrokes, so a binding with no keystrokes (existing.keystrokes() == None) cannot be located and the function refuses rather than corrupting the file.","triggerScenarios":"The remove flow invoked on a binding that carries no keystrokes — e.g. an action-only entry or a partially constructed binding object — so the KeybindUpdateOperation::Remove target would have nothing to match against in the JSON.","commonSituations":"UI race where the binding list was refreshed mid-edit; entries synthesized from defaults rather than user keymap contents; stale code paths calling remove on non-keystroke bindings.","solutions":["Only enable 'Remove keybinding' UI actions when the selected binding has keystrokes","For bindings that live in the default keymap, add an overriding entry instead of removing","Edit the user keymap.json directly (via keymap editor open-file) to delete the stale block","Check whether the binding came from a bundled keymap that the removal flow cannot modify by design"],"exampleFix":"// before\nlet Some(keystrokes) = existing.keystrokes() else {\n    anyhow::bail!(\"Cannot remove a keybinding that does not exist\");\n};\n\n// after (caller gates the action)\nlet can_remove = existing.keystrokes().is_some();\n// ... .when(can_remove, |row| row.mouse_listeners(...))","handlingStrategy":"validation","validationCode":"let Some(keystrokes) = binding.keystrokes() else {\n    // nothing to match in the keymap file; hide the remove affordance\n    return Ok(());\n};","typeGuard":"fn is_removable_binding(b: &ProcessedBinding) -> bool { b.keystrokes().is_some() }","tryCatchPattern":null,"preventionTips":["Gate remove/delete UI on the binding actually having keystrokes","Read back and re-parse the keymap file after edits to catch structural drift","Prefer additive overrides when a binding cannot be matched for removal"],"tags":["zed","keymap","keybinding","removal","validation"],"backgroundTag":"resource-not-found","analyzedSha":"9d272b036335401f339d024ea94968fd51016c40","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}