{"record":{"id":"8a259e967448fb46","repo":"kovidgoyal/kitty","slug":"failed-to-read-from-s-with-error-w-8a259e","errorCode":null,"errorMessage":"Failed to read from %s with error: %w","messagePattern":"Failed to read from (.+?) with error: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/cmd/edit_in_kitty/main.go","lineNumber":196,"sourceCode":"\nfunc edit_in_kitty(path string, opts *Options) (exit_code int, err error) {\n\tread_file, err := os.Open(path)\n\tif err != nil {\n\t\treturn 1, fmt.Errorf(\"Failed to open %s for reading with error: %w\", path, err)\n\t}\n\tdefer read_file.Close()\n\tvar s unix.Stat_t\n\terr = unix.Fstat(int(read_file.Fd()), &s)\n\tif err != nil {\n\t\treturn 1, fmt.Errorf(\"Failed to stat %s with error: %w\", path, err)\n\t}\n\tif s.Size > int64(opts.MaxFileSize)*1024*1024 {\n\t\treturn 1, fmt.Errorf(\"File size %s is too large for performant editing\", humanize.Bytes(uint64(s.Size)))\n\t}\n\n\tfile_data, err := io.ReadAll(read_file)\n\tif err != nil {\n\t\treturn 1, fmt.Errorf(\"Failed to read from %s with error: %w\", path, err)\n\t}\n\tread_file.Close()\n\tdata := strings.Builder{}\n\tdata.Grow(len(file_data) * 4)\n\n\tadd := func(key, val string) {\n\t\tif data.Len() > 0 {\n\t\t\tdata.WriteString(\",\")\n\t\t}\n\t\tdata.WriteString(key)\n\t\tdata.WriteString(\"=\")\n\t\tdata.WriteString(val)\n\t}\n\tadd_encoded := func(key, val string) { add(key, encode(val)) }\n\n\tif unix.Access(path, unix.R_OK|unix.W_OK) != nil {\n\t\treturn 1, fmt.Errorf(\"%s is not readable and writeable\", path)\n\t}","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/tools/cmd/edit_in_kitty/main.go#L178-L214","documentation":"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.","triggerScenarios":"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.","commonSituations":"Reading from failing disks (EIO), disconnected sshfs/NFS mounts, or editing a log file while logrotate rotates/truncates it.","solutions":["Check dmesg/system logs for disk I/O errors; if present the storage is the problem","Retry after remounting network filesystems; copy the file locally first","If a rotating log is the target, edit a snapshot copy (cp first) instead of the live file","Verify with: cat <file> > /dev/null to see if plain reads also fail"],"exampleFix":"# before\nedit-in-kitty /var/log/app/live.log   # truncated mid-read by logrotate\n# after\ncp /var/log/app/live.log /tmp/edit.log && edit-in-kitty /tmp/edit.log","handlingStrategy":"retry","validationCode":"// Verify the file reads cleanly before launching the editor\nif f, err := os.Open(path); err == nil {\n    defer f.Close()\n    if _, err := io.Copy(io.Discard, io.LimitReader(f, 1<<20)); err != nil {\n        return fmt.Errorf(\"file unreadable (I/O error): %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"Failed to read from\") {\n    time.Sleep(200 * time.Millisecond) // transient NFS/FUSE hiccup\n    // retry once; if it persists, copy the file locally and edit the copy\n}","preventionTips":["Snapshot rotating logs before editing (cp then edit the copy)","Copy files off flaky network mounts before opening them in the editor"],"tags":["filesystem","io-error","concurrent-modification","go"],"backgroundTag":"file-read-failed","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}