[{"data":1,"prerenderedAt":1570},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-valueerror-io-operation-on-closed-file-with-excelwriter":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-valueerror-io-operation-on-closed-file-with-excelwriter":1534,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-valueerror-io-operation-on-closed-file-with-excelwriter":1543,"children:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-valueerror-io-operation-on-closed-file-with-excelwriter":1548,"related:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-valueerror-io-operation-on-closed-file-with-excelwriter":1549},{"id":4,"title":5,"body":6,"dateModified":1500,"datePublished":1500,"description":1501,"extension":1502,"faq":1503,"keyword":1512,"kind":1513,"meta":1514,"navigation":306,"path":1523,"seo":1524,"slug":1527,"stem":1528,"topics":1529,"type":1532,"__hash__":1533},"docs\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-valueerror-io-operation-on-closed-file-with-excelwriter\u002Findex.md","Fix \"ValueError: I\u002FO operation on closed file\" with ExcelWriter",{"type":7,"value":8,"toc":1486},"minimark",[9,43,48,76,79,83,103,220,224,274,278,501,523,649,653,866,909,976,980,1002,1006,1101,1135,1296,1300,1327,1331,1387,1391,1406,1410,1416,1422,1437,1449,1453,1482],[10,11,12,16,17,20,21,24,25,29,30,33,34,36,37,42],"p",{},[13,14,15],"code",{},"ValueError: I\u002FO operation on closed file"," is Python's way of saying that something tried to read from or write to a file object that had already been closed. With pandas' ",[13,18,19],{},"ExcelWriter"," it nearly always comes from the order of ",[13,22,23],{},"with"," blocks: the workbook is only written to its destination when the writer ",[26,27,28],"em",{},"closes",", so if the destination — a file handle or an in-memory buffer — is closed first, the final write fails. The traceback points at ",[13,31,32],{},"close()"," or the end of a ",[13,35,23],{}," block, not at the line that caused the problem, which makes it confusing. This page reproduces the three common causes, explains what actually happened to the file, shows the fix for each, and covers a fourth case that is worse because it raises no error at all. It belongs to ",[38,39,41],"a",{"href":40},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002F","Troubleshooting Common Python Excel Errors",".",[44,45,47],"h2",{"id":46},"prerequisites","Prerequisites",[49,50,55],"pre",{"className":51,"code":52,"language":53,"meta":54,"style":54},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[13,56,57],{"__ignoreMap":54},[58,59,62,66,70,73],"span",{"class":60,"line":61},"line",1,[58,63,65],{"class":64},"sMTad","pip",[58,67,69],{"class":68},"srMev"," install",[58,71,72],{"class":68}," pandas",[58,74,75],{"class":68}," openpyxl\n",[10,77,78],{},"The examples use the default openpyxl engine; XlsxWriter behaves the same way for these cases.",[44,80,82],{"id":81},"why-the-timing-matters","Why the timing matters",[10,84,85,87,88,91,92,95,96,98,99,102],{},[13,86,19],{}," collects sheets in memory while ",[13,89,90],{},"to_excel"," is called, and only builds the ",[13,93,94],{},".xlsx"," package — a zip archive — and writes it out when it is closed, either explicitly with ",[13,97,32],{}," or at the end of a ",[13,100,101],{},"with pd.ExcelWriter(...)"," block. Until then, the destination has received nothing. Anything that closes the destination before that moment leaves the writer with nowhere to write.",[104,105,113,114,113,118,113,122,113,130,113,140,113,147,113,152,113,158,113,163,113,167,113,172,113,175,113,179,113,182,113,187,113,193,113,196,113,200,113,204,113,207,113,212,113,217],"svg",{"viewBox":106,"role":107,"ariaLabelledBy":108,"xmlns":111,"style":112},"4 0 752 108","img",[109,110],"io-timing-t","io-timing-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[115,116,117],"title",{"id":109},"When ExcelWriter actually writes",[119,120,121],"desc",{"id":110},"Creating the writer opens nothing yet for a path or keeps a reference to a handle. Each to_excel call adds a sheet in memory. Only close, or the end of the with block, builds the zip and writes it to the destination, which must still be open at that moment.",[123,124],"rect",{"x":125,"y":126,"width":127,"height":128,"fill":129},"4","0","752","108","#ffffff",[123,131],{"x":132,"y":133,"width":134,"height":135,"rx":136,"fill":137,"stroke":138,"style":139},"20.0","16.0","153.0","76.5","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[141,142,146],"text",{"x":143,"y":144,"style":145},"96.5","50.2","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","ExcelWriter(dest)",[141,148,151],{"x":143,"y":149,"style":150},"69.8","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","nothing written yet",[60,153],{"x1":154,"y1":155,"x2":156,"y2":155,"stroke":157,"style":139},"178.0","54.2","200.0","var(--brand,#5b5cf0)",[159,160],"polygon",{"points":161,"fill":162},"204.0,54.2 195.0,59.2 195.0,49.2","#5b5cf0",[123,164],{"x":165,"y":133,"width":134,"height":135,"rx":136,"fill":166,"stroke":157,"style":139},"209.0","#f0f4ff",[141,168,171],{"x":169,"y":144,"style":170},"285.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","to_excel(…)",[141,173,174],{"x":169,"y":149,"style":150},"sheets kept in memory",[60,176],{"x1":177,"y1":155,"x2":178,"y2":155,"stroke":157,"style":139},"367.0","389.0",[159,180],{"points":181,"fill":162},"393.0,54.2 384.0,59.2 384.0,49.2",[123,183],{"x":184,"y":133,"width":134,"height":135,"rx":136,"fill":185,"stroke":186,"style":139},"398.0","#fdefd8","var(--gold,#b4740a)",[141,188,192],{"x":189,"y":190,"style":191},"474.5","41.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","close() \u002F end of",[141,194,23],{"x":189,"y":195,"style":191},"59.0",[141,197,199],{"x":189,"y":198,"style":150},"78.5","zip built and written",[60,201],{"x1":202,"y1":155,"x2":203,"y2":155,"stroke":157,"style":139},"556.0","578.0",[159,205],{"points":206,"fill":162},"582.0,54.2 573.0,59.2 573.0,49.2",[123,208],{"x":209,"y":133,"width":134,"height":135,"rx":136,"fill":210,"stroke":211,"style":139},"587.0","#fce9e9","var(--danger,#dc2626)",[141,213,216],{"x":214,"y":144,"style":215},"663.5","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Destination",[141,218,219],{"x":214,"y":149,"style":150},"must still be open",[44,221,223],{"id":222},"reading-the-traceback","Reading the traceback",[10,225,226,227,230,231,234,235,238,239,242,243,245,246,248,249,252,253,234,256,259,260,234,263,266,267,270,271,273],{},"The traceback for this error is long and mostly inside pandas, openpyxl and the ",[13,228,229],{},"zipfile"," module, and its last lines usually mention ",[13,232,233],{},"write"," or ",[13,236,237],{},"close"," in one of those libraries. The useful frame is the first one in ",[26,240,241],{},"your"," code: it will be a ",[13,244,32],{}," call or the last line of a ",[13,247,101],{}," block, or a ",[13,250,251],{},"getvalue()",", ",[13,254,255],{},"read()",[13,257,258],{},"read_excel()"," on a buffer. That line is where the closed object was used, but the cause is earlier — wherever that object was closed. Look upwards for the end of a ",[13,261,262],{},"with open(...)",[13,264,265],{},"with io.BytesIO()"," block, an explicit ",[13,268,269],{},".close()",", or a function that returned from inside a ",[13,272,23],{},". The three causes below cover nearly every case seen in practice.",[44,275,277],{"id":276},"cause-1-the-file-handle-closes-before-the-writer","Cause 1 — The file handle closes before the writer",[49,279,283],{"className":280,"code":281,"language":282,"meta":54,"style":54},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\ndf = pd.DataFrame({\"Region\": [\"North\", \"South\"], \"Revenue\": [1200, 860]})\n\ntry:\n    with open(\"report.xlsx\", \"wb\") as f:\n        xw = pd.ExcelWriter(f)\n        df.to_excel(xw, index=False)\n    xw.close()                                         # f is already closed here\nexcept ValueError as e:\n    print(\"ValueError:\", e)\n\nimport os\nprint(\"report.xlsx is\", os.path.getsize(\"report.xlsx\"), \"bytes\")\n","python",[13,284,285,301,308,354,359,368,396,407,425,435,450,464,469,477],{"__ignoreMap":54},[58,286,287,291,295,298],{"class":60,"line":61},[58,288,290],{"class":289},"s-kum","import",[58,292,294],{"class":293},"skGVy"," pandas ",[58,296,297],{"class":289},"as",[58,299,300],{"class":293}," pd\n",[58,302,304],{"class":60,"line":303},2,[58,305,307],{"emptyLinePlaceholder":306},true,"\n",[58,309,311,314,317,320,323,326,329,331,334,337,340,342,346,348,351],{"class":60,"line":310},3,[58,312,313],{"class":293},"df ",[58,315,316],{"class":289},"=",[58,318,319],{"class":293}," pd.DataFrame({",[58,321,322],{"class":68},"\"Region\"",[58,324,325],{"class":293},": [",[58,327,328],{"class":68},"\"North\"",[58,330,252],{"class":293},[58,332,333],{"class":68},"\"South\"",[58,335,336],{"class":293},"], ",[58,338,339],{"class":68},"\"Revenue\"",[58,341,325],{"class":293},[58,343,345],{"class":344},"sP0c6","1200",[58,347,252],{"class":293},[58,349,350],{"class":344},"860",[58,352,353],{"class":293},"]})\n",[58,355,357],{"class":60,"line":356},4,[58,358,307],{"emptyLinePlaceholder":306},[58,360,362,365],{"class":60,"line":361},5,[58,363,364],{"class":289},"try",[58,366,367],{"class":293},":\n",[58,369,371,374,377,380,383,385,388,391,393],{"class":60,"line":370},6,[58,372,373],{"class":289},"    with",[58,375,376],{"class":344}," open",[58,378,379],{"class":293},"(",[58,381,382],{"class":68},"\"report.xlsx\"",[58,384,252],{"class":293},[58,386,387],{"class":68},"\"wb\"",[58,389,390],{"class":293},") ",[58,392,297],{"class":289},[58,394,395],{"class":293}," f:\n",[58,397,399,402,404],{"class":60,"line":398},7,[58,400,401],{"class":293},"        xw ",[58,403,316],{"class":289},[58,405,406],{"class":293}," pd.ExcelWriter(f)\n",[58,408,410,413,417,419,422],{"class":60,"line":409},8,[58,411,412],{"class":293},"        df.to_excel(xw, ",[58,414,416],{"class":415},"sa561","index",[58,418,316],{"class":289},[58,420,421],{"class":344},"False",[58,423,424],{"class":293},")\n",[58,426,428,431],{"class":60,"line":427},9,[58,429,430],{"class":293},"    xw.close()                                         ",[58,432,434],{"class":433},"s-wDw","# f is already closed here\n",[58,436,438,441,444,447],{"class":60,"line":437},10,[58,439,440],{"class":289},"except",[58,442,443],{"class":344}," ValueError",[58,445,446],{"class":289}," as",[58,448,449],{"class":293}," e:\n",[58,451,453,456,458,461],{"class":60,"line":452},11,[58,454,455],{"class":344},"    print",[58,457,379],{"class":293},[58,459,460],{"class":68},"\"ValueError:\"",[58,462,463],{"class":293},", e)\n",[58,465,467],{"class":60,"line":466},12,[58,468,307],{"emptyLinePlaceholder":306},[58,470,472,474],{"class":60,"line":471},13,[58,473,290],{"class":289},[58,475,476],{"class":293}," os\n",[58,478,480,483,485,488,491,493,496,499],{"class":60,"line":479},14,[58,481,482],{"class":344},"print",[58,484,379],{"class":293},[58,486,487],{"class":68},"\"report.xlsx is\"",[58,489,490],{"class":293},", os.path.getsize(",[58,492,382],{"class":68},[58,494,495],{"class":293},"), ",[58,497,498],{"class":68},"\"bytes\"",[58,500,424],{"class":293},[10,502,503,504,506,507,510,511,514,515,518,519,522],{},"The writer is given an open file handle, the sheet is added, and then the ",[13,505,262],{}," block ends and closes the handle. When ",[13,508,509],{},"xw.close()"," runs, it builds the workbook and tries to write it to ",[13,512,513],{},"f",", which is closed: ",[13,516,517],{},"ValueError",". The file exists, because ",[13,520,521],{},"open(..., \"wb\")"," created it, but it is empty — zero bytes — and Excel will say it is corrupt. The fix is to nest the blocks so the writer closes first, inside the handle's block, or simpler still, to pass the path and let pandas open and close the file itself. Passing a handle is only worth it when something else owns the file — a temporary file, a network stream, an archive member — and in that case the writer's block must sit entirely inside the owner's:",[49,524,526],{"className":280,"code":525,"language":282,"meta":54,"style":54},"with open(\"report.xlsx\", \"wb\") as f:\n    with pd.ExcelWriter(f) as xw:                      # writer closes first, then the handle\n        df.to_excel(xw, index=False)\nprint(\"nested:\", os.path.getsize(\"report.xlsx\"), \"bytes\")\n\nwith pd.ExcelWriter(\"report.xlsx\") as xw:              # or just pass the path\n    df.to_excel(xw, index=False)\nprint(\"path:\", os.path.getsize(\"report.xlsx\"), \"bytes\")\n",[13,527,528,548,563,575,594,598,617,630],{"__ignoreMap":54},[58,529,530,532,534,536,538,540,542,544,546],{"class":60,"line":61},[58,531,23],{"class":289},[58,533,376],{"class":344},[58,535,379],{"class":293},[58,537,382],{"class":68},[58,539,252],{"class":293},[58,541,387],{"class":68},[58,543,390],{"class":293},[58,545,297],{"class":289},[58,547,395],{"class":293},[58,549,550,552,555,557,560],{"class":60,"line":303},[58,551,373],{"class":289},[58,553,554],{"class":293}," pd.ExcelWriter(f) ",[58,556,297],{"class":289},[58,558,559],{"class":293}," xw:                      ",[58,561,562],{"class":433},"# writer closes first, then the handle\n",[58,564,565,567,569,571,573],{"class":60,"line":310},[58,566,412],{"class":293},[58,568,416],{"class":415},[58,570,316],{"class":289},[58,572,421],{"class":344},[58,574,424],{"class":293},[58,576,577,579,581,584,586,588,590,592],{"class":60,"line":356},[58,578,482],{"class":344},[58,580,379],{"class":293},[58,582,583],{"class":68},"\"nested:\"",[58,585,490],{"class":293},[58,587,382],{"class":68},[58,589,495],{"class":293},[58,591,498],{"class":68},[58,593,424],{"class":293},[58,595,596],{"class":60,"line":361},[58,597,307],{"emptyLinePlaceholder":306},[58,599,600,602,605,607,609,611,614],{"class":60,"line":370},[58,601,23],{"class":289},[58,603,604],{"class":293}," pd.ExcelWriter(",[58,606,382],{"class":68},[58,608,390],{"class":293},[58,610,297],{"class":289},[58,612,613],{"class":293}," xw:              ",[58,615,616],{"class":433},"# or just pass the path\n",[58,618,619,622,624,626,628],{"class":60,"line":398},[58,620,621],{"class":293},"    df.to_excel(xw, ",[58,623,416],{"class":415},[58,625,316],{"class":289},[58,627,421],{"class":344},[58,629,424],{"class":293},[58,631,632,634,636,639,641,643,645,647],{"class":60,"line":409},[58,633,482],{"class":344},[58,635,379],{"class":293},[58,637,638],{"class":68},"\"path:\"",[58,640,490],{"class":293},[58,642,382],{"class":68},[58,644,495],{"class":293},[58,646,498],{"class":68},[58,648,424],{"class":293},[44,650,652],{"id":651},"cause-2-a-buffer-returned-from-inside-its-own-with-block","Cause 2 — A buffer returned from inside its own with block",[49,654,656],{"className":280,"code":655,"language":282,"meta":54,"style":54},"import io\n\ndef build_report_broken(df):\n    with io.BytesIO() as buf:\n        with pd.ExcelWriter(buf) as xw:\n            df.to_excel(xw, index=False)\n        return buf                                     # the with block closes buf on the way out\n\ntry:\n    build_report_broken(df).getvalue()\nexcept ValueError as e:\n    print(\"ValueError:\", e)\n\ndef build_report(df):\n    buf = io.BytesIO()\n    with pd.ExcelWriter(buf) as xw:\n        df.to_excel(xw, index=False)\n    return buf.getvalue()                              # return the bytes, not the buffer\n\ndata = build_report(df)\nprint(len(data), \"bytes, starts with\", data[:2])\n",[13,657,658,665,669,681,693,706,719,730,734,740,745,755,765,769,778,789,800,813,825,830,841],{"__ignoreMap":54},[58,659,660,662],{"class":60,"line":61},[58,661,290],{"class":289},[58,663,664],{"class":293}," io\n",[58,666,667],{"class":60,"line":303},[58,668,307],{"emptyLinePlaceholder":306},[58,670,671,674,678],{"class":60,"line":310},[58,672,673],{"class":289},"def",[58,675,677],{"class":676},"s_Opv"," build_report_broken",[58,679,680],{"class":293},"(df):\n",[58,682,683,685,688,690],{"class":60,"line":356},[58,684,373],{"class":289},[58,686,687],{"class":293}," io.BytesIO() ",[58,689,297],{"class":289},[58,691,692],{"class":293}," buf:\n",[58,694,695,698,701,703],{"class":60,"line":361},[58,696,697],{"class":289},"        with",[58,699,700],{"class":293}," pd.ExcelWriter(buf) ",[58,702,297],{"class":289},[58,704,705],{"class":293}," xw:\n",[58,707,708,711,713,715,717],{"class":60,"line":370},[58,709,710],{"class":293},"            df.to_excel(xw, ",[58,712,416],{"class":415},[58,714,316],{"class":289},[58,716,421],{"class":344},[58,718,424],{"class":293},[58,720,721,724,727],{"class":60,"line":398},[58,722,723],{"class":289},"        return",[58,725,726],{"class":293}," buf                                     ",[58,728,729],{"class":433},"# the with block closes buf on the way out\n",[58,731,732],{"class":60,"line":409},[58,733,307],{"emptyLinePlaceholder":306},[58,735,736,738],{"class":60,"line":427},[58,737,364],{"class":289},[58,739,367],{"class":293},[58,741,742],{"class":60,"line":437},[58,743,744],{"class":293},"    build_report_broken(df).getvalue()\n",[58,746,747,749,751,753],{"class":60,"line":452},[58,748,440],{"class":289},[58,750,443],{"class":344},[58,752,446],{"class":289},[58,754,449],{"class":293},[58,756,757,759,761,763],{"class":60,"line":466},[58,758,455],{"class":344},[58,760,379],{"class":293},[58,762,460],{"class":68},[58,764,463],{"class":293},[58,766,767],{"class":60,"line":471},[58,768,307],{"emptyLinePlaceholder":306},[58,770,771,773,776],{"class":60,"line":479},[58,772,673],{"class":289},[58,774,775],{"class":676}," build_report",[58,777,680],{"class":293},[58,779,781,784,786],{"class":60,"line":780},15,[58,782,783],{"class":293},"    buf ",[58,785,316],{"class":289},[58,787,788],{"class":293}," io.BytesIO()\n",[58,790,792,794,796,798],{"class":60,"line":791},16,[58,793,373],{"class":289},[58,795,700],{"class":293},[58,797,297],{"class":289},[58,799,705],{"class":293},[58,801,803,805,807,809,811],{"class":60,"line":802},17,[58,804,412],{"class":293},[58,806,416],{"class":415},[58,808,316],{"class":289},[58,810,421],{"class":344},[58,812,424],{"class":293},[58,814,816,819,822],{"class":60,"line":815},18,[58,817,818],{"class":289},"    return",[58,820,821],{"class":293}," buf.getvalue()                              ",[58,823,824],{"class":433},"# return the bytes, not the buffer\n",[58,826,828],{"class":60,"line":827},19,[58,829,307],{"emptyLinePlaceholder":306},[58,831,833,836,838],{"class":60,"line":832},20,[58,834,835],{"class":293},"data ",[58,837,316],{"class":289},[58,839,840],{"class":293}," build_report(df)\n",[58,842,844,846,848,851,854,857,860,863],{"class":60,"line":843},21,[58,845,482],{"class":344},[58,847,379],{"class":293},[58,849,850],{"class":344},"len",[58,852,853],{"class":293},"(data), ",[58,855,856],{"class":68},"\"bytes, starts with\"",[58,858,859],{"class":293},", data[:",[58,861,862],{"class":344},"2",[58,864,865],{"class":293},"])\n",[10,867,868,869,872,873,875,876,879,880,234,882,885,886,888,889,892,893,896,897,900,901,904,905,42],{},"Building a workbook in memory is common in web apps and email jobs, and ",[13,870,871],{},"with io.BytesIO() as buf:"," looks tidy. But a ",[13,874,23],{}," block closes its object when it exits — including when it exits through ",[13,877,878],{},"return"," — so the caller receives a closed buffer, and the first ",[13,881,251],{},[13,883,884],{},"read_excel"," fails. The fix is not to manage the buffer with ",[13,887,23],{}," at all: a ",[13,890,891],{},"BytesIO"," holds only memory and needs no closing, and returning ",[13,894,895],{},"buf.getvalue()"," hands the caller plain bytes, which cannot be closed. The bytes start with ",[13,898,899],{},"PK",", the signature of a zip archive, which is a quick sanity check that a real workbook was produced. A test can assert exactly that — ",[13,902,903],{},"data[:2] == b\"PK\""," and a non-trivial length — without opening the workbook at all. Sending those bytes from a web endpoint is covered in ",[38,906,908],{"href":907},"\u002Fautomating-reporting-workflows\u002Fserving-excel-files-from-python-web-apps\u002Fbuild-an-excel-workbook-in-memory-with-bytesio\u002F","Build an Excel Workbook in Memory with BytesIO",[104,910,113,915,113,918,113,921,113,924,113,929,113,935,113,941,113,946,113,950,113,954,113,958,113,963,113,967,113,970,113,973],{"viewBox":911,"role":107,"ariaLabelledBy":912,"xmlns":111,"style":112},"4 0 752 173",[913,914],"io-buffer-t","io-buffer-d",[115,916,917],{"id":913},"Returning a buffer or returning bytes",[119,919,920],{"id":914},"Returning a BytesIO from inside a with block hands back a closed buffer, and getvalue raises ValueError. Creating the buffer without with and returning getvalue hands back bytes that are always usable.",[123,922],{"x":125,"y":126,"width":127,"height":923,"fill":129},"173",[123,925],{"x":132,"y":133,"width":926,"height":927,"rx":928,"fill":210,"stroke":211,"style":139},"351.0","141.0","14",[141,930,934],{"x":931,"y":932,"style":933},"195.5","44.0","font-size:14px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","with BytesIO() as buf: … return buf",[60,936],{"x1":937,"y1":938,"x2":939,"y2":938,"stroke":211,"style":940},"36.0","57.0","355.0","stroke-width:1px",[141,942,945],{"x":931,"y":943,"style":944},"77.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","buffer closed on return",[141,947,949],{"x":931,"y":948,"style":944},"103.0","getvalue raises ValueError",[141,951,953],{"x":931,"y":952,"style":944},"129.0","read_excel raises ValueError",[123,955],{"x":178,"y":133,"width":926,"height":927,"rx":928,"fill":956,"stroke":957,"style":139},"#d9f4f1","var(--teal,#0f9488)",[141,959,962],{"x":960,"y":932,"style":961},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","buf = BytesIO() … return buf.getvalue()",[60,964],{"x1":965,"y1":938,"x2":966,"y2":938,"stroke":957,"style":940},"405.0","724.0",[141,968,969],{"x":960,"y":943,"style":944},"plain bytes returned",[141,971,972],{"x":960,"y":948,"style":944},"cannot be closed",[141,974,975],{"x":960,"y":952,"style":944},"starts with PK",[44,977,979],{"id":978},"cause-3-reading-a-buffer-after-it-was-closed","Cause 3 — Reading a buffer after it was closed",[10,981,982,983,986,987,234,990,993,994,997,998,1001],{},"The same error appears on the reading side when a buffer is passed to ",[13,984,985],{},"pd.read_excel"," after something closed it — for example an upload handler that reads the request's file object once, closes it, and then hands it to a second function. A closed buffer cannot be reopened. Read the bytes once with ",[13,988,989],{},".read()",[13,991,992],{},".getvalue()",", keep the bytes, and wrap them in a fresh ",[13,995,996],{},"io.BytesIO(data)"," for each reader that needs a file-like object. This also avoids the subtler cousin of the error, where the buffer is open but its position is at the end after a first read, so the second reader sees an empty file; ",[13,999,1000],{},"buf.seek(0)"," fixes that one.",[44,1003,1005],{"id":1004},"the-silent-case-writing-after-the-with-block","The silent case — writing after the with block",[49,1007,1009],{"className":280,"code":1008,"language":282,"meta":54,"style":54},"with pd.ExcelWriter(\"two_sheets.xlsx\") as xw:\n    df.to_excel(xw, sheet_name=\"Summary\", index=False)\ndf.to_excel(xw, sheet_name=\"Detail\", index=False)     # after the block: no error at all\n\nwith pd.ExcelFile(\"two_sheets.xlsx\") as book:\n    print(book.sheet_names)\n",[13,1010,1011,1026,1048,1074,1078,1094],{"__ignoreMap":54},[58,1012,1013,1015,1017,1020,1022,1024],{"class":60,"line":61},[58,1014,23],{"class":289},[58,1016,604],{"class":293},[58,1018,1019],{"class":68},"\"two_sheets.xlsx\"",[58,1021,390],{"class":293},[58,1023,297],{"class":289},[58,1025,705],{"class":293},[58,1027,1028,1030,1033,1035,1038,1040,1042,1044,1046],{"class":60,"line":303},[58,1029,621],{"class":293},[58,1031,1032],{"class":415},"sheet_name",[58,1034,316],{"class":289},[58,1036,1037],{"class":68},"\"Summary\"",[58,1039,252],{"class":293},[58,1041,416],{"class":415},[58,1043,316],{"class":289},[58,1045,421],{"class":344},[58,1047,424],{"class":293},[58,1049,1050,1053,1055,1057,1060,1062,1064,1066,1068,1071],{"class":60,"line":310},[58,1051,1052],{"class":293},"df.to_excel(xw, ",[58,1054,1032],{"class":415},[58,1056,316],{"class":289},[58,1058,1059],{"class":68},"\"Detail\"",[58,1061,252],{"class":293},[58,1063,416],{"class":415},[58,1065,316],{"class":289},[58,1067,421],{"class":344},[58,1069,1070],{"class":293},")     ",[58,1072,1073],{"class":433},"# after the block: no error at all\n",[58,1075,1076],{"class":60,"line":356},[58,1077,307],{"emptyLinePlaceholder":306},[58,1079,1080,1082,1085,1087,1089,1091],{"class":60,"line":361},[58,1081,23],{"class":289},[58,1083,1084],{"class":293}," pd.ExcelFile(",[58,1086,1019],{"class":68},[58,1088,390],{"class":293},[58,1090,297],{"class":289},[58,1092,1093],{"class":293}," book:\n",[58,1095,1096,1098],{"class":60,"line":370},[58,1097,455],{"class":344},[58,1099,1100],{"class":293},"(book.sheet_names)\n",[10,1102,1103,1104,1106,1107,1109,1110,1113,1114,1117,1118,1121,1122,1124,1125,1127,1128,1130,1131,42],{},"This one raises nothing, which makes it the most dangerous. The second ",[13,1105,90],{}," call is outside the ",[13,1108,23],{}," block, after the writer has already written and closed the file. pandas accepts the call — the sheet is added to the writer's in-memory book — but nothing will ever write that book again, so the file on disk contains only ",[26,1111,1112],{},"Summary",". There is no error and no warning; the ",[26,1115,1116],{},"Detail"," sheet is simply missing. It typically happens after a refactor moves a line out of an indented block, or when code that used to call ",[13,1119,1120],{},"writer.close()"," explicitly at the end is converted to a ",[13,1123,23],{}," block and one call is left behind below it. Running a linter does not catch it, because the code is valid; only checking the output does. The protection is to keep every ",[13,1126,90],{}," for a writer inside its ",[13,1129,23],{}," block, and to check the sheet names of important outputs after writing, as in ",[38,1132,1134],{"href":1133},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fvalidate-an-excel-report-before-sending-it\u002F","Validate an Excel Report Before Sending It",[104,1136,113,1142,113,1145,113,1148,113,1153,113,1158,113,1162,113,1168,113,1172,113,1176,113,1180,113,1184,113,1188,113,1192,113,1195,113,1199,113,1201,113,1204,113,1206,113,1209,113,1212,113,1215,113,1217,113,1220,113,1222,113,1225,113,1227,113,1230,113,1233,113,1237,113,1239,113,1242,113,1244,113,1247,113,1249,113,1252,113,1255,113,1258,113,1260,113,1263,113,1265,113,1268,113,1270,113,1273,113,1276,113,1280,113,1282,113,1285,113,1287,113,1291,113,1293],{"viewBox":1137,"role":107,"ariaLabelledBy":1138,"xmlns":111,"style":1141},"75 0 610 196",[1139,1140],"io-cases-t","io-cases-d","width:100%;max-width:610px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[115,1143,1144],{"id":1139},"The four cases and their fixes",[119,1146,1147],{"id":1140},"A handle closed before the writer gives ValueError and an empty file; nest the writer inside. A buffer returned from a with block gives ValueError on use; return getvalue. A closed buffer passed to read_excel gives ValueError; keep the bytes. Writing after the with block raises nothing and loses the sheet; keep writes inside.",[123,1149],{"x":1150,"y":126,"width":1151,"height":1152,"fill":129},"75","610","196",[123,1154],{"x":1155,"y":133,"width":1156,"height":1157,"rx":126,"fill":137,"stroke":138,"style":940},"91.3","32.0","24.0",[123,1159],{"x":1160,"y":133,"width":1161,"height":1157,"rx":126,"fill":137,"stroke":138,"style":940},"123.3","194.8",[141,1163,1167],{"x":1164,"y":1165,"style":1166},"220.7","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[123,1169],{"x":1170,"y":133,"width":1171,"height":1157,"rx":126,"fill":137,"stroke":138,"style":940},"318.1","166.3",[141,1173,1175],{"x":1174,"y":1165,"style":1166},"401.2","B",[123,1177],{"x":1178,"y":133,"width":1179,"height":1157,"rx":126,"fill":137,"stroke":138,"style":940},"484.4","184.3",[141,1181,1183],{"x":1182,"y":1165,"style":1166},"576.5","C",[123,1185],{"x":1155,"y":1186,"width":1156,"height":1187,"rx":126,"fill":137,"stroke":138,"style":940},"40.0","28.0",[141,1189,1191],{"x":1190,"y":195,"style":1166},"107.3","1",[123,1193],{"x":1160,"y":1186,"width":1161,"height":1187,"rx":126,"fill":166,"stroke":157,"style":1194},"stroke-width:1.5px",[141,1196,1198],{"x":1164,"y":195,"style":1197},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Situation",[123,1200],{"x":1170,"y":1186,"width":1171,"height":1187,"rx":126,"fill":166,"stroke":157,"style":1194},[141,1202,1203],{"x":1174,"y":195,"style":1197},"What you see",[123,1205],{"x":1178,"y":1186,"width":1179,"height":1187,"rx":126,"fill":166,"stroke":157,"style":1194},[141,1207,1208],{"x":1182,"y":195,"style":1197},"Fix",[123,1210],{"x":1155,"y":1211,"width":1156,"height":1187,"rx":126,"fill":137,"stroke":138,"style":940},"68.0",[141,1213,862],{"x":1190,"y":1214,"style":1166},"87.0",[123,1216],{"x":1160,"y":1211,"width":1161,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1218,1219],{"x":1164,"y":1214,"style":944},"Handle closed before writer",[123,1221],{"x":1170,"y":1211,"width":1171,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1223,1224],{"x":1174,"y":1214,"style":944},"ValueError, 0-byte file",[123,1226],{"x":1178,"y":1211,"width":1179,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1228,1229],{"x":1182,"y":1214,"style":944},"nest writer inside handle",[123,1231],{"x":1155,"y":1232,"width":1156,"height":1187,"rx":126,"fill":137,"stroke":138,"style":940},"96.0",[141,1234,1236],{"x":1190,"y":1235,"style":1166},"115.0","3",[123,1238],{"x":1160,"y":1232,"width":1161,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1240,1241],{"x":1164,"y":1235,"style":944},"Buffer returned from with",[123,1243],{"x":1170,"y":1232,"width":1171,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1245,1246],{"x":1174,"y":1235,"style":944},"ValueError on getvalue",[123,1248],{"x":1178,"y":1232,"width":1179,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1250,1251],{"x":1182,"y":1235,"style":944},"return buf.getvalue()",[123,1253],{"x":1155,"y":1254,"width":1156,"height":1187,"rx":126,"fill":137,"stroke":138,"style":940},"124.0",[141,1256,125],{"x":1190,"y":1257,"style":1166},"143.0",[123,1259],{"x":1160,"y":1254,"width":1161,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1261,1262],{"x":1164,"y":1257,"style":944},"Closed buffer to read_excel",[123,1264],{"x":1170,"y":1254,"width":1171,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1266,1267],{"x":1174,"y":1257,"style":944},"ValueError on read",[123,1269],{"x":1178,"y":1254,"width":1179,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1271,1272],{"x":1182,"y":1257,"style":944},"keep bytes; BytesIO(data)",[123,1274],{"x":1155,"y":1275,"width":1156,"height":1187,"rx":126,"fill":137,"stroke":138,"style":940},"152.0",[141,1277,1279],{"x":1190,"y":1278,"style":1166},"171.0","5",[123,1281],{"x":1160,"y":1275,"width":1161,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1283,1284],{"x":1164,"y":1278,"style":944},"to_excel after with block",[123,1286],{"x":1170,"y":1275,"width":1171,"height":1187,"rx":126,"fill":210,"stroke":211,"style":1194},[141,1288,1290],{"x":1174,"y":1278,"style":1289},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","no error; sheet missing",[123,1292],{"x":1178,"y":1275,"width":1179,"height":1187,"rx":126,"fill":129,"stroke":138,"style":940},[141,1294,1295],{"x":1182,"y":1278,"style":944},"keep writes inside",[44,1297,1299],{"id":1298},"a-note-on-writersave","A note on writer.save()",[10,1301,1302,1303,1306,1307,1309,1310,1313,1314,1317,1318,1320,1321,1323,1324,1326],{},"Older code calls ",[13,1304,1305],{},"writer.save()"," instead of ",[13,1308,1120],{},". ",[13,1311,1312],{},"save()"," was deprecated in pandas 1.5 and removed in 2.0; on current versions it raises ",[13,1315,1316],{},"AttributeError: ... object has no attribute 'save'",". Replacing it with ",[13,1319,32],{}," — or, better, a ",[13,1322,23],{}," block — is the fix, and moving to a ",[13,1325,23],{}," block also removes the chance of the ordering mistakes above.",[44,1328,1330],{"id":1329},"common-pitfalls","Common pitfalls",[1332,1333,1334,1342,1357,1366,1375],"ul",{},[1335,1336,1337,1341],"li",{},[1338,1339,1340],"strong",{},"Closing the destination first."," The writer writes on close; close it before the file handle.",[1335,1343,1344,1353,1354,1356],{},[1338,1345,1346,1349,1350,42],{},[13,1347,1348],{},"with BytesIO()"," plus ",[13,1351,1352],{},"return buf"," Return ",[13,1355,895],{}," instead.",[1335,1358,1359,1362,1363,1365],{},[1338,1360,1361],{},"Reusing a consumed buffer."," Keep the bytes and make a new ",[13,1364,891],{}," for each reader.",[1335,1367,1368,1374],{},[1338,1369,1370,1371,1373],{},"Writing after the ",[13,1372,23],{}," block."," No error, but the sheet is lost.",[1335,1376,1377,1381,1382,1384,1385,1373],{},[1338,1378,1379,42],{},[13,1380,1305],{}," Removed in pandas 2; use ",[13,1383,32],{}," or a ",[13,1386,23],{},[44,1388,1390],{"id":1389},"conclusion","Conclusion",[10,1392,1393,1394,1396,1397,1399,1400,1402,1403,1405],{},"\"I\u002FO operation on closed file\" from ExcelWriter means the destination was closed before the writer wrote to it, or a buffer was used after closing. Let the writer close first — nest it inside any file handle, or pass a path — return ",[13,1395,895],{}," rather than a buffer from inside a ",[13,1398,23],{}," block, and keep bytes rather than buffers when several readers need the data. Keep every ",[13,1401,90],{}," call inside the writer's ",[13,1404,23],{}," block, because writing afterwards fails silently.",[44,1407,1409],{"id":1408},"frequently-asked-questions","Frequently asked questions",[10,1411,1412,1415],{},[1338,1413,1414],{},"Why does ExcelWriter raise \"I\u002FO operation on closed file\"?","\nThe writer writes the workbook when it closes; if the file handle or buffer it writes to was closed first, that final write fails.",[10,1417,1418,1421],{},[1338,1419,1420],{},"Why is my Excel file 0 bytes after this error?","\nThe file was created when the handle was opened, but the workbook was never written to it because the handle closed before the writer did.",[10,1423,1424,1427,1428,1430,1431,1433,1434,1436],{},[1338,1425,1426],{},"How do I return an Excel file from a function in memory?","\nWrite to a ",[13,1429,891],{}," without a ",[13,1432,23],{}," block and return ",[13,1435,895],{},", which gives plain bytes.",[10,1438,1439,1442,1444,1445,1448],{},[1338,1440,1441],{},"What replaced ExcelWriter.save()?",[13,1443,32],{},", or simply using ",[13,1446,1447],{},"with pd.ExcelWriter(...) as writer:"," so the writer closes automatically.",[44,1450,1452],{"id":1451},"related","Related",[1332,1454,1455,1461,1468,1475],{},[1335,1456,1457,1458,1460],{},"Up one level: ",[38,1459,41],{"href":40}," — common errors and fixes.",[1335,1462,1463,1467],{},[38,1464,1466],{"href":1465},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fwrite-multiple-dataframes-to-one-excel-file\u002F","Write Multiple DataFrames to One Excel File"," — using one writer for many sheets.",[1335,1469,1470,1474],{},[38,1471,1473],{"href":1472},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-excel-repaired-content-after-writing-with-python\u002F","Fix \"Excel Found Unreadable Content\" After Writing with Python"," — files that open broken.",[1335,1476,1477,1481],{},[38,1478,1480],{"href":1479},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fwrite-excel-files-atomically-in-python\u002F","Write Excel Files Atomically in Python"," — never leave an empty file behind.",[1483,1484,1485],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":54,"searchDepth":303,"depth":303,"links":1487},[1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499],{"id":46,"depth":303,"text":47},{"id":81,"depth":303,"text":82},{"id":222,"depth":303,"text":223},{"id":276,"depth":303,"text":277},{"id":651,"depth":303,"text":652},{"id":978,"depth":303,"text":979},{"id":1004,"depth":303,"text":1005},{"id":1298,"depth":303,"text":1299},{"id":1329,"depth":303,"text":1330},{"id":1389,"depth":303,"text":1390},{"id":1408,"depth":303,"text":1409},{"id":1451,"depth":303,"text":1452},"2026-10-02","pandas raises \"ValueError: I\u002FO operation on closed file\" when an ExcelWriter or the buffer it wrote to is used after it was closed: a file handle whose with block ended before the writer, a BytesIO returned from inside its own with block, or a buffer read after close. Reproduce each case, see why the file ends up empty, fix the order of the blocks, and catch the silent variant where writing after the with block loses a sheet without any error.","md",[1504,1506,1508,1510],{"q":1414,"a":1505},"The writer writes the workbook when it closes; if the file handle or buffer it writes to was closed first, that final write fails.",{"q":1420,"a":1507},"The file was created when the handle was opened, but the workbook was never written to it because the handle closed before the writer did.",{"q":1426,"a":1509},"Write to a BytesIO without a with block and return buf.getvalue(), which gives plain bytes.",{"q":1441,"a":1511},"close(), or simply using with pd.ExcelWriter(...) as writer: so the writer closes automatically.","io operation on closed file excelwriter",null,{"breadcrumb":1515},[1516,1519,1522],{"name":1517,"item":1518},"Home","\u002F",{"name":1520,"item":1521},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":41,"item":40},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-valueerror-io-operation-on-closed-file-with-excelwriter",{"title":1525,"description":1526},"Fix \"I\u002FO operation on closed file\" with pandas ExcelWriter","Fix ValueError I\u002FO operation on closed file with pandas ExcelWriter: file handles closed before the writer, BytesIO returned from a with block, reading closed buffers, and sheets silently lost after the with block.","fix-valueerror-io-operation-on-closed-file-with-excelwriter","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-valueerror-io-operation-on-closed-file-with-excelwriter\u002Findex",[1530,1531],"troubleshooting","writing-excel","how-to","L6siH8t7UQ8tz8qxZFfE8eaRn1AF7EqgTLeBaEJSzGc",[1535,1539],{"title":1536,"path":1537,"stem":1538,"children":-1},"Fix \"Usecols do not match columns\" in pandas read_excel","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-usecols-do-not-match-columns-error-in-pandas","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-usecols-do-not-match-columns-error-in-pandas\u002Findex",{"title":1540,"path":1541,"stem":1542,"children":-1},"Fix the win32com gen_py AttributeError (CLSIDToClassMap)","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-win32com-gen-py-attributeerror","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-win32com-gen-py-attributeerror\u002Findex",[1544,1546],{"path":1545,"title":1520},"\u002Fgetting-started-with-python-excel-automation",{"path":1547,"title":41},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors",[],[1550,1554,1557,1560,1563,1566],{"path":1551,"title":1552,"kind":1553},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fhandle-permission-denied-when-writing-excel-in-python","Handle Permission Denied When Writing Excel in Python","fix",{"path":1555,"title":1556,"kind":1532},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook","What openpyxl Loses When You Save an Existing Workbook",{"path":1558,"title":1559,"kind":1553},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffix-excel-serial-numbers-showing-instead-of-dates","Fix Excel Serial Numbers Showing Instead of Dates",{"path":1561,"title":1562,"kind":1532},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fhandle-daylight-saving-time-in-excel-timestamps","Handle Daylight Saving Time in Excel Timestamps",{"path":1564,"title":1565,"kind":1532},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002Fhandle-microsoft-graph-throttling-for-excel","Handle Microsoft Graph Throttling in Excel Automation",{"path":1567,"title":1568,"kind":1569},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation","Error Handling and Logging in Excel Automation","guide",1790972067638]