{"record":{"id":"922a50036a9352d8","repo":"charmbracelet/crush","slug":"error-reading-image-file-w","errorCode":null,"errorMessage":"error reading image file: %w","messagePattern":"error reading image file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/view.go","lineNumber":216,"sourceCode":"\t\t\t\t} else {\n\t\t\t\t\tparams.Limit = DefaultReadLimit\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tisSupportedImage, mimeType := getImageMimeType(filePath)\n\t\t\tif isSupportedImage {\n\t\t\t\tif fileInfo.Size() > MaxViewSize {\n\t\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"Image file is too large (%d bytes). Maximum size is %d bytes\",\n\t\t\t\t\t\tfileInfo.Size(), MaxViewSize)), nil\n\t\t\t\t}\n\t\t\t\tif !GetSupportsImagesFromContext(ctx) {\n\t\t\t\t\tmodelName := GetModelNameFromContext(ctx)\n\t\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"This model (%s) does not support image data.\", modelName)), nil\n\t\t\t\t}\n\n\t\t\t\timageData, readErr := os.ReadFile(filePath)\n\t\t\t\tif readErr != nil {\n\t\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"error reading image file: %w\", readErr)\n\t\t\t\t}\n\n\t\t\t\t// Some tools save files with a mismatched extension\n\t\t\t\t// (e.g. pinchtab writes JPEG bytes to a .png file).\n\t\t\t\t// Providers like Anthropic strictly validate the\n\t\t\t\t// media type against the base64 magic bytes and 400\n\t\t\t\t// on mismatch, so prefer the sniffed type whenever\n\t\t\t\t// it identifies a supported image format.\n\t\t\t\tmimeType = sniffImageMimeType(imageData, mimeType)\n\n\t\t\t\treturn fantasy.NewImageResponse(imageData, mimeType), nil\n\t\t\t}\n\n\t\t\t// Read the file content\n\t\t\tmaxContentSize := MaxViewSize\n\t\t\tif isSkillFile {\n\t\t\t\tmaxContentSize = 0\n\t\t\t}","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/view.go#L198-L234","documentation":"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.","triggerScenarios":"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.","commonSituations":"Generated screenshots/artifacts in tmpdirs cleaned up concurrently; images on network shares that dropped; files owned by another user with mode 0600.","solutions":["Read the wrapped cause and fix it (permissions, path, mount)","Confirm the image still exists and is readable by the process user (ls -l)","Retry — transient I/O errors on network mounts often succeed on a second attempt","Copy the image to an accessible location before viewing"],"exampleFix":"// before\n// screenshot deleted between stat and read\n// after\ncp /tmp/app/screenshot.png ~/shots/ && view ~/shots/screenshot.png","handlingStrategy":"retry","validationCode":"f, err := os.Open(path)\nif err != nil {\n    return fmt.Errorf(\"image %q unreadable: %w\", path, err)\n}\nf.Close()","typeGuard":"func readableImage(path string) bool {\n    f, err := os.Open(path)\n    if err != nil { return false }\n    f.Close()\n    return true\n}","tryCatchPattern":"var pe *fs.PathError\nif errors.As(err, &pe) {\n    if pe.Err == syscall.EACCES || os.IsNotExist(pe.Err) {\n        // fix perms / regenerate the image, then retry\n    }\n}","preventionTips":["Copy generated images to a stable, user-readable location before viewing","Don't delete or chmod files while the tool is reading them","Retry transient failures on network-mounted storage"],"tags":["filesystem","io","image","read-failure"],"backgroundTag":"file-read-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}