micro-editor/micro · warning
bindings is locked by the user
Error message
bindings is locked by the user
What it means
Returned by TryBindKeyPlug (internal/action/bindings.go:268) when the global setting "lockbindings" is true. This API is the plugin-facing binding entry point: it intentionally refuses to add or change keybindings while the user has locked them, so plugins cannot hijack keys. The error is a policy rejection, not a malfunction; TryBindKey (the user path) is unaffected.
Source
Thrown at internal/action/bindings.go:268
if len(seq1.keys) != len(seq2.keys) {
return false
}
for i := 0; i < len(seq1.keys); i++ {
if seq1.keys[i] != seq2.keys[i] {
return false
}
}
return true
}
return e1 == e2
}
// TryBindKeyPlug tries to bind a key for the plugin without writing to bindings.json.
// This operation can be rejected by lockbindings to prevent unexpected actions by the user.
func TryBindKeyPlug(k, v string, overwrite bool) (bool, error) {
if l, ok := config.GlobalSettings["lockbindings"]; ok && l.(bool) {
return false, errors.New("bindings is locked by the user")
}
return TryBindKey(k, v, overwrite, false)
}
// TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json
// Returns true if the keybinding already existed or is binded successfully and a possible error
func TryBindKey(k, v string, overwrite bool, writeToFile bool) (bool, error) {
var e error
var parsed map[string]any
filename := filepath.Join(config.ConfigDir, "bindings.json")
createBindingsIfNotExist(filename)
if _, e = os.Stat(filename); e == nil {
input, err := os.ReadFile(filename)
if err != nil {
return false, errors.New("Error reading bindings.json file: " + err.Error())
}
View on GitHub (pinned to 1c8b82b32e)
Solutions
- Set "lockbindings": false in ~/.config/micro/settings.json (or via > set lockbindings false) and reload the plugin
- If you are the plugin user, bind the plugin's keys yourself in bindings.json, which bypasses TryBindKeyPlug
- If you are the plugin author, check bindings lock before binding and surface a friendly notice instead of failing (see defense snippet)
Example fix
-- before (lua plugin init.lua)
bindings.TryBindKeyplug("F9", "filemanager.toggle", true)
-- after: tolerate a locked bindings map
local ok, err = pcall(bindings.TryBindKeyplug, "F9", "filemanager.toggle", true)
if not ok or err then
messenger.Info("filemanager: bindings locked; map F9 manually")
end Defensive patterns
Strategy: validation
Validate before calling
-- Lua plugin: honor the user's lock before attempting to bind
if config.GetGlobalOption("lockbindings") then
messenger.Info("bindings locked by user; skipping key registration")
return
end
bindings.TryBindKeyplug("F9", "myplugin.toggle", true) Try / catch
-- Lua equivalent of try-catch
local ok, err = pcall(bindings.TryBindKeyplug, "F9", "myplugin.toggle", true)
if not ok or (err and tostring(err):find("locked", 1, true)) then
messenger.Info("myplugin: keybinding skipped (lockbindings enabled)")
end Prevention
- Document that your plugin binds keys and how lockbindings suppresses it
- Offer a manual snippet users can paste into bindings.json instead
- Never retry in a loop when the lock error arrives — it's a deliberate policy
When it happens
Trigger: settings.json contains "lockbindings": true and an installed Lua plugin calls bindings.TryBindKeyplug(...) during init or at runtime (e.g. filemanager, lsp-style plugins registering shortcuts). The call returns (false, this error) and no binding is created.
Common situations: User enabled lockbindings after plugin trouble, then updated/reinstalled plugins that re-register keys; sharing settings.json across machines where the plugin expectation differs; plugin authors testing without realizing the lock is global.
Related errors
- Invalid event %s
- %s is not a bindable event
- Error reading bindings.json file: %s
- Error reading bindings.json: %s
- Cannot save scratch buffer
AI-assisted analysis of micro-editor/micro@1c8b82b32e (2026-08-15).
Data as JSON: /api/errors/722cb2747de61b79.
Report an issue: GitHub.