openpyxl: ValueError: I/O operation on closed file


I used this code to put an image logo.png in logo.xlsx at cell A1:

from openpyxl import Workbook
from openpyxl.drawing.image import Image
wb = Workbook()
ws =
img = Image('logo.png')
ws.add_image(img, 'A1')'logo.xlsx')

now I am trying to read this file as existing workbook using load_workbook, using this code:

from openpyxl import load_workbook
wb = load_workbook('./logo.xlsx')'logo_new.xlsx')

but I am getting following error:

Traceback (most recent call last):
  File "c:UsersSarmad GulzarDocumentsVisual Studio", line 3, in <module>"new3.xlsx")
  File "", line 391, in save
    save_workbook(self, filename)
  File "", line 284, in save_workbook
  File "", line 266, in save
  File "", line 85, in write_data
  File "", line 122, in _write_images
    self._archive.writestr(img.path[1:], img._data())
  File "", line 64, in _data
    img = _import_image(self.ref)
  File "", line 33, in _import_image
    img =
  File "", line 2638, in open
ValueError: I/O operation on closed file.

P.S: I tried doing the same thing to a file which had no images. It worked just fine.

Asked By: Sarmad Gulzar



I was using openpyxl version 2.5.14. Downgrading to 2.5.11 fixed it. More information here.

Answered By: Sarmad Gulzar

After wasting time by searching for a fix, this was my solution:
I had the same problem with openpyxl 2.5.14, but downgrading on 2.5.11 don’t solve the problem at all, use 2.5.12 instead.

If you use 2.5.11 it is possible that no new image will display on your excel file.
this is a known problem if there are already images in the file to edit.

Best practise:
If the rest of your code runs with openpyxl 2.6.2 or 2.6.1 use one of this versions, here this problem is solved by a library update!
fixed on version 2.6.0 issue #1170

Answered By: droebi

I am hitting this error in openpyxl 3.1.2, when trying to add images that I have in memory. The issue is how drawing.images.Image._data works, where it tries to reaccess the underlying image, which it can’t in the in-memory case. Here is my solution, which overrides the _data:

def add_img_bytes_to_sheet(sheet: Worksheet, cell: Cell, img_bytes: bytes) -> None:
    """Add image bytes to a cell, wrapping how the data is accessed.
    Otherwise, there is a "IO on closed file" error. We overwrite the `_data()`
    method on an openpyxl image, making sure that the wrapper is independent for
    each image.
    bio = BytesIO(img_bytes)
    pilimage =
    image = openpyxl.drawing.image.Image(pilimage)
    def data_fillin(imgb: bytes) -> Callable[[], bytes]:
        bobj = bytes(imgb)
        def wrap() -> bytes:
            return bobj
        return wrap
    image._data = data_fillin(img_bytes)
    image.anchor = f"{cell.column_letter}{cell.row}"
Answered By: Yakov Pechersky
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.