kovidgoyal/kitty · error

Failed to read from %s with error: %w

Error message

Failed to read from %s with error: %w

What it means

io.ReadAll on the already-opened file failed. Since open and fstat succeeded, a read error here usually means the file became unreadable mid-read (I/O error, filesystem went away, permission changed via ACL) or the file grew/truncated concurrently producing inconsistent reads.

Source

Thrown at tools/cmd/edit_in_kitty/main.go:196

func edit_in_kitty(path string, opts *Options) (exit_code int, err error) {
	read_file, err := os.Open(path)
	if err != nil {
		return 1, fmt.Errorf("Failed to open %s for reading with error: %w", path, err)
	}
	defer read_file.Close()
	var s unix.Stat_t
	err = unix.Fstat(int(read_file.Fd()), &s)
	if err != nil {
		return 1, fmt.Errorf("Failed to stat %s with error: %w", path, err)
	}
	if s.Size > int64(opts.MaxFileSize)*1024*1024 {
		return 1, fmt.Errorf("File size %s is too large for performant editing", humanize.Bytes(uint64(s.Size)))
	}

	file_data, err := io.ReadAll(read_file)
	if err != nil {
		return 1, fmt.Errorf("Failed to read from %s with error: %w", path, err)
	}
	read_file.Close()
	data := strings.Builder{}
	data.Grow(len(file_data) * 4)

	add := func(key, val string) {
		if data.Len() > 0 {
			data.WriteString(",")
		}
		data.WriteString(key)
		data.WriteString("=")
		data.WriteString(val)
	}
	add_encoded := func(key, val string) { add(key, encode(val)) }

	if unix.Access(path, unix.R_OK|unix.W_OK) != nil {
		return 1, fmt.Errorf("%s is not readable and writeable", path)
	}

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Check dmesg/system logs for disk I/O errors; if present the storage is the problem
  2. Retry after remounting network filesystems; copy the file locally first
  3. If a rotating log is the target, edit a snapshot copy (cp first) instead of the live file
  4. Verify with: cat <file> > /dev/null to see if plain reads also fail

Example fix

# before
edit-in-kitty /var/log/app/live.log   # truncated mid-read by logrotate
# after
cp /var/log/app/live.log /tmp/edit.log && edit-in-kitty /tmp/edit.log
Defensive patterns

Strategy: retry

Validate before calling

// Verify the file reads cleanly before launching the editor
if f, err := os.Open(path); err == nil {
    defer f.Close()
    if _, err := io.Copy(io.Discard, io.LimitReader(f, 1<<20)); err != nil {
        return fmt.Errorf("file unreadable (I/O error): %w", err)
    }
}

Try / catch

if err != nil && strings.Contains(err.Error(), "Failed to read from") {
    time.Sleep(200 * time.Millisecond) // transient NFS/FUSE hiccup
    // retry once; if it persists, copy the file locally and edit the copy
}

Prevention

When it happens

Trigger: edit_in_kitty opens the file, then during io.ReadAll the underlying storage returns EIO/ESTALE, the file is truncated by another writer, or a removable/network mount drops.

Common situations: Reading from failing disks (EIO), disconnected sshfs/NFS mounts, or editing a log file while logrotate rotates/truncates it.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/8a259e967448fb46. Report an issue: GitHub.