micro-editor/micro · error

Error reading bindings.json file: %s

Error message

Error reading bindings.json file: %s

What it means

Returned by TryBindKey (internal/action/bindings.go:284) when os.Stat says bindings.json exists but os.ReadFile then fails. The stat-succeeds/read-fails window means an I/O problem rather than a missing file: permission denied on the file or a config directory, the file being replaced by a directory between calls, or flaky media. The raw OS error is appended for diagnosis.

Source

Thrown at internal/action/bindings.go:284

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())
		}

		err = json5.Unmarshal(input, &parsed)
		if err != nil {
			return false, errors.New("Error reading bindings.json: " + err.Error())
		}

		key, err := findEvent(k)
		if err != nil {
			return false, err
		}

		found := false
		var ev string
		for ev = range parsed {
			if e, err := findEvent(ev); err == nil {
				if eventsEqual(e, key) {
					found = true

View on GitHub (pinned to 1c8b82b32e)

Solutions

  1. Fix ownership/perms: sudo chown -R $USER: ~/.config/micro && chmod 644 ~/.config/micro/bindings.json
  2. If bindings.json is somehow a directory: rm -rf ~/.config/micro/bindings.json and let micro recreate it ('{}')
  3. Check filesystem health: df -h ~ and dmesg | tail for I/O errors; remount a read-only home rw
  4. As a last resort move the file away: mv bindings.json bindings.json.broken (createBindingsIfNotExist writes a fresh '{}')

Example fix

// before: bindings.json owned by root after 'sudo micro'
$ ls -l ~/.config/micro/bindings.json
-rw------- 1 root root 542 ... bindings.json
> bind CtrlQ QuitAll  ->  Error reading bindings.json file: ... permission denied

// after
$ sudo chown $USER:$USER ~/.config/micro/bindings.json
$ chmod 644 ~/.config/micro/bindings.json
Defensive patterns

Strategy: validation

Validate before calling

// Ensure bindings.json is readable before any bind call
func bindingsReadable() error {
    p := filepath.Join(config.ConfigDir, "bindings.json")
    fi, err := os.Stat(p)
    if err != nil { return err }
    if !fi.Mode().IsRegular() { return fmt.Errorf("%s is not a regular file", p) }
    f, err := os.Open(p)
    if err != nil { return err } // surfaces permission errors early
    return f.Close()
}

Try / catch

if _, err := action.TryBindKey(k, v, true, true); err != nil {
    if strings.HasPrefix(err.Error(), "Error reading bindings.json file") {
        // permissions/IO: prompt the user to fix ownership instead of retrying
        return fmt.Errorf("fix permissions on bindings.json: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Executing > bind ... when bindings.json is unreadable: mode 000, owned by another user (classic after running micro once with sudo), a directory named bindings.json, or a read-only/filesystem-full home.

Common situations: Ran 'sudo micro' for one root-owned edit, leaving root-owned ~/.config/micro/bindings.json; home on NFS with permission mapping; disk quota exhausted so read syscalls fail.

Related errors


AI-assisted analysis of micro-editor/micro@1c8b82b32e (2026-08-15). Data as JSON: /api/errors/761f18fb277c9f6d. Report an issue: GitHub.