charmbracelet/crush · error

error reading image file: %w

Error message

error reading image file: %w

What it means

The target is a supported image and os.ReadFile(filePath) failed after the size check and stat succeeded — meaning the file became unreadable between stat and read, or I/O failed. Common wrapped causes: EACCES (permissions changed), EIO, or the file being deleted in the race window.

Source

Thrown at internal/agent/tools/view.go:216

				} else {
					params.Limit = DefaultReadLimit
				}
			}

			isSupportedImage, mimeType := getImageMimeType(filePath)
			if isSupportedImage {
				if fileInfo.Size() > MaxViewSize {
					return fantasy.NewTextErrorResponse(fmt.Sprintf("Image file is too large (%d bytes). Maximum size is %d bytes",
						fileInfo.Size(), MaxViewSize)), nil
				}
				if !GetSupportsImagesFromContext(ctx) {
					modelName := GetModelNameFromContext(ctx)
					return fantasy.NewTextErrorResponse(fmt.Sprintf("This model (%s) does not support image data.", modelName)), nil
				}

				imageData, readErr := os.ReadFile(filePath)
				if readErr != nil {
					return fantasy.ToolResponse{}, fmt.Errorf("error reading image file: %w", readErr)
				}

				// Some tools save files with a mismatched extension
				// (e.g. pinchtab writes JPEG bytes to a .png file).
				// Providers like Anthropic strictly validate the
				// media type against the base64 magic bytes and 400
				// on mismatch, so prefer the sniffed type whenever
				// it identifies a supported image format.
				mimeType = sniffImageMimeType(imageData, mimeType)

				return fantasy.NewImageResponse(imageData, mimeType), nil
			}

			// Read the file content
			maxContentSize := MaxViewSize
			if isSkillFile {
				maxContentSize = 0
			}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Read the wrapped cause and fix it (permissions, path, mount)
  2. Confirm the image still exists and is readable by the process user (ls -l)
  3. Retry — transient I/O errors on network mounts often succeed on a second attempt
  4. Copy the image to an accessible location before viewing

Example fix

// before
// screenshot deleted between stat and read
// after
cp /tmp/app/screenshot.png ~/shots/ && view ~/shots/screenshot.png
Defensive patterns

Strategy: retry

Validate before calling

f, err := os.Open(path)
if err != nil {
    return fmt.Errorf("image %q unreadable: %w", path, err)
}
f.Close()

Type guard

func readableImage(path string) bool {
    f, err := os.Open(path)
    if err != nil { return false }
    f.Close()
    return true
}

Try / catch

var pe *fs.PathError
if errors.As(err, &pe) {
    if pe.Err == syscall.EACCES || os.IsNotExist(pe.Err) {
        // fix perms / regenerate the image, then retry
    }
}

Prevention

When it happens

Trigger: Image file deleted or permissions revoked between os.Stat and os.ReadFile; I/O errors on failing disks or network mounts; reading images on volumes with intermittent access.

Common situations: Generated screenshots/artifacts in tmpdirs cleaned up concurrently; images on network shares that dropped; files owned by another user with mode 0600.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/922a50036a9352d8. Report an issue: GitHub.