wavetermdev/waveterm · error

reading file %s: %w

Error message

reading file %s: %w

What it means

Wraps os.ReadFile(filePath) failure when a `wsh ai` argument is a regular file. os.Stat succeeded but the actual read failed — most commonly permission denied on the file itself, an I/O error, or the file being removed between Stat and Read. The wrapped error (*fs.PathError with EBADF/EACCES/EIO/EISDIR etc.) is preserved via %w.

Source

Thrown at cmd/wsh/cmd/wshcmd-ai.go:132

				return fmt.Errorf("getting absolute path for %s: %w", filePath, err)
			}

			if fileInfo.IsDir() {
				result, err := fileutil.ReadDir(filePath, 500)
				if err != nil {
					return fmt.Errorf("reading directory %s: %w", filePath, err)
				}
				jsonData, err := json.Marshal(result)
				if err != nil {
					return fmt.Errorf("marshaling directory listing for %s: %w", filePath, err)
				}
				data = jsonData
				fileName = absPath
				mimeType = "directory"
			} else {
				data, err = os.ReadFile(filePath)
				if err != nil {
					return fmt.Errorf("reading file %s: %w", filePath, err)
				}
				fileName = absPath
				mimeType = detectMimeType(data)
			}
		}

		isPDF := mimeType == "application/pdf"
		isImage := strings.HasPrefix(mimeType, "image/")
		isDirectory := mimeType == "directory"

		if !isPDF && !isImage && !isDirectory {
			mimeType = "text/plain"
			if utilfn.ContainsBinaryData(data) {
				return fmt.Errorf("file %s contains binary data and cannot be uploaded as text", fileName)
			}
		}

		maxSize, sizeStr := getMaxFileSize(mimeType)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check readability: `cat <file> >/dev/null`; fix with chmod/chown or use sudo to copy it somewhere readable first.
  2. Re-check the file still exists (`ls -l <file>`) — handle deletion races in scripts.
  3. If it's a fifo/device/symlink to one, attach a regular file (e.g. `cp` or dump contents to a temp file first).
  4. Investigate disk/mount health if the wrapped error is EIO.

Example fix

// before
$ wsh ai /var/log/syslog
// error: reading file /var/log/syslog: open ...: permission denied
// after
$ sudo cat /var/log/syslog | wsh ai -
Defensive patterns

Strategy: validation

Validate before calling

for f in "$@"; do
  if [ -f "$f" ] && ! [ -r "$f" ]; then
    echo "file not readable: $f" >&2; exit 1
  fi
done

Try / catch

if err := runAI(args); err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) {
        switch {
        case errors.Is(perr.Err, syscall.EACCES):
            return fmt.Errorf("no read permission on %q; chmod/copy first", perr.Path)
        case errors.Is(perr.Err, syscall.EIO):
            return fmt.Errorf("I/O error reading %q; check disk/mount health", perr.Path)
        }
    }
    return err
}

Prevention

When it happens

Trigger: `wsh ai <file>` where the file exists but is not readable by the current user (Stat can succeed via parent dir +x without file r), the file is a special device/fifo that fails on read, it was deleted between Stat and ReadFile, or hardware/IO errors occur.

Common situations: Reading logs owned by root as a normal user; attaching files on a dying disk or full/failed mount; scripts racing with file deletion; attaching /dev files by mistake.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/ee7b27b9171bb191. Report an issue: GitHub.