[{"data":1,"prerenderedAt":2613},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-typeerror-expected-class":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-typeerror-expected-class":2578,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-typeerror-expected-class":2586,"children:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-typeerror-expected-class":2591,"related:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-typeerror-expected-class":2592},{"id":4,"title":5,"body":6,"dateModified":2544,"datePublished":2544,"description":2545,"extension":2546,"faq":2547,"keyword":2556,"kind":2557,"meta":2558,"navigation":302,"path":2567,"seo":2568,"slug":2571,"stem":2572,"topics":2573,"type":2576,"__hash__":2577},"docs\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-typeerror-expected-class\u002Findex.md","Fix openpyxl \"TypeError: expected \u003Cclass ...>\"",{"type":7,"value":8,"toc":2531},"minimark",[9,22,32,41,46,69,72,250,254,261,572,582,586,611,860,863,991,995,1009,1202,1229,1300,1303,1384,1391,1617,1624,1712,1783,1787,1799,1926,1950,1954,1969,2200,2210,2214,2225,2375,2378,2382,2430,2434,2462,2466,2472,2478,2484,2490,2494,2528],[10,11,12,13,17,18,21],"p",{},"openpyxl models the Excel file format with typed attributes: a font size must be a number, a fill must be a ",[14,15,16],"code",{},"Fill"," object, a colour must be a ",[14,19,20],{},"Color",". When code assigns something else, openpyxl raises one of these:",[23,24,30],"pre",{"className":25,"code":27,"language":28,"meta":29},[26],"language-text","TypeError: expected \u003Cclass 'float'>\nTypeError: expected \u003Cclass 'openpyxl.styles.fills.Fill'>\nTypeError: \u003Cclass 'openpyxl.styles.fonts.Font'>.color should be \u003Cclass 'openpyxl.styles.colors.Color'> but value is \u003Cclass 'tuple'>\n","text","",[14,31,27],{"__ignoreMap":29},[10,33,34,35,40],{},"The class in the message is what openpyxl wanted; the job is to find which assignment gave it something else. Usually that is the line in the traceback. Sometimes it is not: a few mistakes are accepted silently and fail only when the workbook is saved, with a traceback that points into openpyxl's writer. This page covers both. It is part of ",[36,37,39],"a",{"href":38},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002F","Troubleshooting Common Python Excel Errors",".",[42,43,45],"h2",{"id":44},"prerequisites","Prerequisites",[23,47,51],{"className":48,"code":49,"language":50,"meta":29,"style":29},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl\n","bash",[14,52,53],{"__ignoreMap":29},[54,55,58,62,66],"span",{"class":56,"line":57},"line",1,[54,59,61],{"class":60},"sMTad","pip",[54,63,65],{"class":64},"srMev"," install",[54,67,68],{"class":64}," openpyxl\n",[10,70,71],{},"The examples use openpyxl 3.1. Each one reproduces the error, then shows the fix.",[73,74,82,83,82,87,82,91,82,99,82,109,82,120,82,126,82,131,82,135,82,141,82,146,82,150,82,157,82,163,82,167,82,171,82,174,82,177,82,183,82,187,82,190,82,194,82,197,82,202,82,209,82,214,82,217,82,220,82,224,82,227,82,232,82,239,82,244,82,247],"svg",{"viewBox":75,"role":76,"ariaLabelledBy":77,"xmlns":80,"style":81},"4 0 752 142","img",[78,79],"te-flow-t","te-flow-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  ",[84,85,86],"title",{"id":78},"How openpyxl checks a value",[88,89,90],"desc",{"id":79},"A value is assigned to an attribute. openpyxl's descriptor tries to convert it to the expected type. If conversion succeeds the value is stored; if it fails, a TypeError names the expected class. Some assignments bypass the check and fail when the file is written.",[92,93],"rect",{"x":94,"y":95,"width":96,"height":97,"fill":98},"4","0","752","142","#ffffff",[92,100],{"x":101,"y":102,"width":103,"height":104,"rx":105,"fill":106,"stroke":107,"style":108},"20.0","16.0","115.2","110.5","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[110,111,113],"g",{"transform":112},"translate(65.6,29.0) scale(1.000)",[114,115],"path",{"d":116,"fill":117,"stroke":118,"style":119},"M9 8l-4 4 4 4 M15 8l4 4-4 4","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[28,121,125],{"x":122,"y":123,"style":124},"77.6","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Assignment",[28,127,130],{"x":122,"y":128,"style":129},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","font.size =",[28,132,134],{"x":122,"y":133,"style":129},"112.5","'large'",[56,136],{"x1":137,"y1":138,"x2":139,"y2":138,"stroke":140,"style":108},"140.2","71.2","162.2","var(--brand,#5b5cf0)",[142,143],"polygon",{"points":144,"fill":145},"166.2,71.2 157.2,76.2 157.2,66.2","#5b5cf0",[92,147],{"x":148,"y":102,"width":103,"height":104,"rx":105,"fill":149,"stroke":140,"style":108},"171.2","#f0f4ff",[110,151,153],{"transform":152},"translate(216.8,37.8) scale(1.000)",[114,154],{"d":155,"fill":117,"stroke":156,"style":119},"M3 5h18l-7 8v6l-4 2v-8z","var(--brand-strong,#4338ca)",[28,158,162],{"x":159,"y":160,"style":161},"228.8","84.2","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Descriptor",[28,164,166],{"x":159,"y":165,"style":129},"103.8","expected type",[56,168],{"x1":169,"y1":138,"x2":170,"y2":138,"stroke":140,"style":108},"291.4","313.4",[142,172],{"points":173,"fill":145},"317.4,71.2 308.4,76.2 308.4,66.2",[92,175],{"x":176,"y":102,"width":103,"height":104,"rx":105,"fill":149,"stroke":140,"style":108},"322.4",[110,178,180],{"transform":179},"translate(368.0,37.8) scale(1.000)",[114,181],{"d":182,"fill":117,"stroke":156,"style":119},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7",[28,184,186],{"x":185,"y":160,"style":161},"380.0","Convert",[28,188,189],{"x":185,"y":165,"style":129},"float('large')",[56,191],{"x1":192,"y1":138,"x2":193,"y2":138,"stroke":140,"style":108},"442.6","464.6",[142,195],{"points":196,"fill":145},"468.6,71.2 459.6,76.2 459.6,66.2",[92,198],{"x":199,"y":102,"width":103,"height":104,"rx":105,"fill":200,"stroke":201,"style":108},"473.6","#fce9e9","var(--danger,#dc2626)",[110,203,205],{"transform":204},"translate(519.2,29.0) scale(1.000)",[114,206],{"d":207,"fill":117,"stroke":208,"style":119},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--accent-ink,#be185d)",[28,210,213],{"x":211,"y":123,"style":212},"531.2","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Fails",[28,215,216],{"x":211,"y":128,"style":129},"TypeError",[28,218,219],{"x":211,"y":133,"style":129},"names the class",[56,221],{"x1":222,"y1":138,"x2":223,"y2":138,"stroke":140,"style":108},"593.8","615.8",[142,225],{"points":226,"fill":145},"619.8,71.2 610.8,76.2 610.8,66.2",[92,228],{"x":229,"y":102,"width":103,"height":104,"rx":105,"fill":230,"stroke":231,"style":108},"624.8","#fdefd8","var(--gold,#b4740a)",[110,233,235],{"transform":234},"translate(670.4,29.0) scale(1.000)",[114,236],{"d":237,"fill":117,"stroke":238,"style":119},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","var(--gold-ink,#7a4e06)",[28,240,243],{"x":241,"y":123,"style":242},"682.4","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Or at save",[28,245,246],{"x":241,"y":128,"style":129},"stylesheet",[28,248,249],{"x":241,"y":133,"style":129},"writer",[42,251,253],{"id":252},"case-1-expected-class-float-a-number-that-is-not-a-number","Case 1 — expected \u003Cclass 'float'>: a number that is not a number",[10,255,256,257,260],{},"Numeric attributes such as font size, column width, row height and chart style try to convert the value with ",[14,258,259],{},"float()",". A numeric string converts; a word does not:",[23,262,266],{"className":263,"code":264,"language":265,"meta":29,"style":29},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nwb = Workbook()\nws = wb.active\n\nfor label, action in [\n    (\"Font(size='12')\", lambda: Font(size=\"12\")),\n    (\"Font(size='large')\", lambda: Font(size=\"large\")),\n    (\"column width 'wide'\", lambda: setattr(ws.column_dimensions[\"A\"], \"width\", \"wide\")),\n    (\"column width None\", lambda: setattr(ws.column_dimensions[\"A\"], \"width\", None)),\n]:\n    try:\n        action()\n        print(f\"{label:22} accepted\")\n    except TypeError as e:\n        print(f\"{label:22} TypeError: {e}\")\n","python",[14,267,268,284,297,304,316,327,332,347,377,400,438,469,475,484,490,524,539],{"__ignoreMap":29},[54,269,270,274,278,281],{"class":56,"line":57},[54,271,273],{"class":272},"s-kum","from",[54,275,277],{"class":276},"skGVy"," openpyxl ",[54,279,280],{"class":272},"import",[54,282,283],{"class":276}," Workbook\n",[54,285,287,289,292,294],{"class":56,"line":286},2,[54,288,273],{"class":272},[54,290,291],{"class":276}," openpyxl.styles ",[54,293,280],{"class":272},[54,295,296],{"class":276}," Font\n",[54,298,300],{"class":56,"line":299},3,[54,301,303],{"emptyLinePlaceholder":302},true,"\n",[54,305,307,310,313],{"class":56,"line":306},4,[54,308,309],{"class":276},"wb ",[54,311,312],{"class":272},"=",[54,314,315],{"class":276}," Workbook()\n",[54,317,319,322,324],{"class":56,"line":318},5,[54,320,321],{"class":276},"ws ",[54,323,312],{"class":272},[54,325,326],{"class":276}," wb.active\n",[54,328,330],{"class":56,"line":329},6,[54,331,303],{"emptyLinePlaceholder":302},[54,333,335,338,341,344],{"class":56,"line":334},7,[54,336,337],{"class":272},"for",[54,339,340],{"class":276}," label, action ",[54,342,343],{"class":272},"in",[54,345,346],{"class":276}," [\n",[54,348,350,353,356,359,362,365,369,371,374],{"class":56,"line":349},8,[54,351,352],{"class":276},"    (",[54,354,355],{"class":64},"\"Font(size='12')\"",[54,357,358],{"class":276},", ",[54,360,361],{"class":272},"lambda",[54,363,364],{"class":276},": Font(",[54,366,368],{"class":367},"sa561","size",[54,370,312],{"class":272},[54,372,373],{"class":64},"\"12\"",[54,375,376],{"class":276},")),\n",[54,378,380,382,385,387,389,391,393,395,398],{"class":56,"line":379},9,[54,381,352],{"class":276},[54,383,384],{"class":64},"\"Font(size='large')\"",[54,386,358],{"class":276},[54,388,361],{"class":272},[54,390,364],{"class":276},[54,392,368],{"class":367},[54,394,312],{"class":272},[54,396,397],{"class":64},"\"large\"",[54,399,376],{"class":276},[54,401,403,405,408,410,412,415,419,422,425,428,431,433,436],{"class":56,"line":402},10,[54,404,352],{"class":276},[54,406,407],{"class":64},"\"column width 'wide'\"",[54,409,358],{"class":276},[54,411,361],{"class":272},[54,413,414],{"class":276},": ",[54,416,418],{"class":417},"sP0c6","setattr",[54,420,421],{"class":276},"(ws.column_dimensions[",[54,423,424],{"class":64},"\"A\"",[54,426,427],{"class":276},"], ",[54,429,430],{"class":64},"\"width\"",[54,432,358],{"class":276},[54,434,435],{"class":64},"\"wide\"",[54,437,376],{"class":276},[54,439,441,443,446,448,450,452,454,456,458,460,462,464,467],{"class":56,"line":440},11,[54,442,352],{"class":276},[54,444,445],{"class":64},"\"column width None\"",[54,447,358],{"class":276},[54,449,361],{"class":272},[54,451,414],{"class":276},[54,453,418],{"class":417},[54,455,421],{"class":276},[54,457,424],{"class":64},[54,459,427],{"class":276},[54,461,430],{"class":64},[54,463,358],{"class":276},[54,465,466],{"class":417},"None",[54,468,376],{"class":276},[54,470,472],{"class":56,"line":471},12,[54,473,474],{"class":276},"]:\n",[54,476,478,481],{"class":56,"line":477},13,[54,479,480],{"class":272},"    try",[54,482,483],{"class":276},":\n",[54,485,487],{"class":56,"line":486},14,[54,488,489],{"class":276},"        action()\n",[54,491,493,496,499,502,505,509,512,515,518,521],{"class":56,"line":492},15,[54,494,495],{"class":417},"        print",[54,497,498],{"class":276},"(",[54,500,501],{"class":272},"f",[54,503,504],{"class":64},"\"",[54,506,508],{"class":507},"sSjpA","{",[54,510,511],{"class":276},"label",[54,513,514],{"class":272},":22",[54,516,517],{"class":507},"}",[54,519,520],{"class":64}," accepted\"",[54,522,523],{"class":276},")\n",[54,525,527,530,533,536],{"class":56,"line":526},16,[54,528,529],{"class":272},"    except",[54,531,532],{"class":417}," TypeError",[54,534,535],{"class":272}," as",[54,537,538],{"class":276}," e:\n",[54,540,542,544,546,548,550,552,554,556,558,561,563,566,568,570],{"class":56,"line":541},17,[54,543,495],{"class":417},[54,545,498],{"class":276},[54,547,501],{"class":272},[54,549,504],{"class":64},[54,551,508],{"class":507},[54,553,511],{"class":276},[54,555,514],{"class":272},[54,557,517],{"class":507},[54,559,560],{"class":64}," TypeError: ",[54,562,508],{"class":507},[54,564,565],{"class":276},"e",[54,567,517],{"class":507},[54,569,504],{"class":64},[54,571,523],{"class":276},[10,573,574,575,578,579,40],{},"The values usually come from a config file or a spreadsheet of settings, where \"12\" is fine and \"large\" or an empty cell is not. Validate settings when you load them, not when openpyxl rejects them. Resetting a column to its default width is ",[14,576,577],{},"del ws.column_dimensions[\"A\"]",", not ",[14,580,581],{},"width = None",[42,583,585],{"id":584},"case-2-should-be-class-color-but-value-is-class-tuple","Case 2 — should be \u003Cclass 'Color'> but value is \u003Cclass 'tuple'>",[10,587,588,589,591,592,595,596,599,600,602,603,606,607,610],{},"Colours are the most common source. openpyxl accepts a ",[14,590,20],{}," object or an aRGB hex string: six hex digits (",[14,593,594],{},"FF0000",") or eight with alpha (",[14,597,598],{},"FFFF0000","). RGB tuples raise a ",[14,601,216],{},"; CSS-style strings with ",[14,604,605],{},"#"," and colour names raise a ",[14,608,609],{},"ValueError",":",[23,612,614],{"className":263,"code":613,"language":265,"meta":29,"style":29},"from openpyxl.styles import PatternFill\n\nfor label, action in [\n    (\"Font(color=(255, 0, 0))\", lambda: Font(color=(255, 0, 0))),\n    (\"Font(color='#FF0000')\", lambda: Font(color=\"#FF0000\")),\n    (\"PatternFill(fgColor='red')\", lambda: PatternFill(\"solid\", fgColor=\"red\")),\n    (\"Font(color='FF0000')\", lambda: Font(color=\"FF0000\")),\n]:\n    try:\n        action()\n        print(f\"{label:28} accepted\")\n    except (TypeError, ValueError) as e:\n        print(f\"{label:28} {type(e).__name__}: {str(e)[:70]}\")\n",[14,615,616,627,631,641,675,697,726,748,752,758,762,785,806],{"__ignoreMap":29},[54,617,618,620,622,624],{"class":56,"line":57},[54,619,273],{"class":272},[54,621,291],{"class":276},[54,623,280],{"class":272},[54,625,626],{"class":276}," PatternFill\n",[54,628,629],{"class":56,"line":286},[54,630,303],{"emptyLinePlaceholder":302},[54,632,633,635,637,639],{"class":56,"line":299},[54,634,337],{"class":272},[54,636,340],{"class":276},[54,638,343],{"class":272},[54,640,346],{"class":276},[54,642,643,645,648,650,652,654,657,659,661,664,666,668,670,672],{"class":56,"line":306},[54,644,352],{"class":276},[54,646,647],{"class":64},"\"Font(color=(255, 0, 0))\"",[54,649,358],{"class":276},[54,651,361],{"class":272},[54,653,364],{"class":276},[54,655,656],{"class":367},"color",[54,658,312],{"class":272},[54,660,498],{"class":276},[54,662,663],{"class":417},"255",[54,665,358],{"class":276},[54,667,95],{"class":417},[54,669,358],{"class":276},[54,671,95],{"class":417},[54,673,674],{"class":276},"))),\n",[54,676,677,679,682,684,686,688,690,692,695],{"class":56,"line":318},[54,678,352],{"class":276},[54,680,681],{"class":64},"\"Font(color='#FF0000')\"",[54,683,358],{"class":276},[54,685,361],{"class":272},[54,687,364],{"class":276},[54,689,656],{"class":367},[54,691,312],{"class":272},[54,693,694],{"class":64},"\"#FF0000\"",[54,696,376],{"class":276},[54,698,699,701,704,706,708,711,714,716,719,721,724],{"class":56,"line":329},[54,700,352],{"class":276},[54,702,703],{"class":64},"\"PatternFill(fgColor='red')\"",[54,705,358],{"class":276},[54,707,361],{"class":272},[54,709,710],{"class":276},": PatternFill(",[54,712,713],{"class":64},"\"solid\"",[54,715,358],{"class":276},[54,717,718],{"class":367},"fgColor",[54,720,312],{"class":272},[54,722,723],{"class":64},"\"red\"",[54,725,376],{"class":276},[54,727,728,730,733,735,737,739,741,743,746],{"class":56,"line":334},[54,729,352],{"class":276},[54,731,732],{"class":64},"\"Font(color='FF0000')\"",[54,734,358],{"class":276},[54,736,361],{"class":272},[54,738,364],{"class":276},[54,740,656],{"class":367},[54,742,312],{"class":272},[54,744,745],{"class":64},"\"FF0000\"",[54,747,376],{"class":276},[54,749,750],{"class":56,"line":349},[54,751,474],{"class":276},[54,753,754,756],{"class":56,"line":379},[54,755,480],{"class":272},[54,757,483],{"class":276},[54,759,760],{"class":56,"line":402},[54,761,489],{"class":276},[54,763,764,766,768,770,772,774,776,779,781,783],{"class":56,"line":440},[54,765,495],{"class":417},[54,767,498],{"class":276},[54,769,501],{"class":272},[54,771,504],{"class":64},[54,773,508],{"class":507},[54,775,511],{"class":276},[54,777,778],{"class":272},":28",[54,780,517],{"class":507},[54,782,520],{"class":64},[54,784,523],{"class":276},[54,786,787,789,792,794,796,798,801,804],{"class":56,"line":471},[54,788,529],{"class":272},[54,790,791],{"class":276}," (",[54,793,216],{"class":417},[54,795,358],{"class":276},[54,797,609],{"class":417},[54,799,800],{"class":276},") ",[54,802,803],{"class":272},"as",[54,805,538],{"class":276},[54,807,808,810,812,814,816,818,820,822,824,827,830,833,836,838,840,842,845,848,851,854,856,858],{"class":56,"line":477},[54,809,495],{"class":417},[54,811,498],{"class":276},[54,813,501],{"class":272},[54,815,504],{"class":64},[54,817,508],{"class":507},[54,819,511],{"class":276},[54,821,778],{"class":272},[54,823,517],{"class":507},[54,825,826],{"class":507}," {",[54,828,829],{"class":417},"type",[54,831,832],{"class":276},"(e).",[54,834,835],{"class":417},"__name__",[54,837,517],{"class":507},[54,839,414],{"class":64},[54,841,508],{"class":507},[54,843,844],{"class":417},"str",[54,846,847],{"class":276},"(e)[:",[54,849,850],{"class":417},"70",[54,852,853],{"class":276},"]",[54,855,517],{"class":507},[54,857,504],{"class":64},[54,859,523],{"class":276},[10,861,862],{},"A small converter keeps colour handling in one place and accepts whatever the rest of your code uses:",[23,864,866],{"className":263,"code":865,"language":265,"meta":29,"style":29},"def to_argb(color):\n    if isinstance(color, tuple):\n        return \"{:02X}{:02X}{:02X}\".format(*color)\n    return color.lstrip(\"#\").upper()\n\nprint(Font(color=to_argb((255, 0, 0))).color.rgb, Font(color=to_argb(\"#1f4e79\")).color.rgb)\n",[14,867,868,880,897,932,946,950],{"__ignoreMap":29},[54,869,870,873,877],{"class":56,"line":57},[54,871,872],{"class":272},"def",[54,874,876],{"class":875},"s_Opv"," to_argb",[54,878,879],{"class":276},"(color):\n",[54,881,882,885,888,891,894],{"class":56,"line":286},[54,883,884],{"class":272},"    if",[54,886,887],{"class":417}," isinstance",[54,889,890],{"class":276},"(color, ",[54,892,893],{"class":417},"tuple",[54,895,896],{"class":276},"):\n",[54,898,899,902,905,907,910,913,915,917,919,921,923,926,929],{"class":56,"line":299},[54,900,901],{"class":272},"        return",[54,903,904],{"class":64}," \"",[54,906,508],{"class":507},[54,908,909],{"class":272},":02X",[54,911,912],{"class":507},"}{",[54,914,909],{"class":272},[54,916,912],{"class":507},[54,918,909],{"class":272},[54,920,517],{"class":507},[54,922,504],{"class":64},[54,924,925],{"class":276},".format(",[54,927,928],{"class":272},"*",[54,930,931],{"class":276},"color)\n",[54,933,934,937,940,943],{"class":56,"line":306},[54,935,936],{"class":272},"    return",[54,938,939],{"class":276}," color.lstrip(",[54,941,942],{"class":64},"\"#\"",[54,944,945],{"class":276},").upper()\n",[54,947,948],{"class":56,"line":318},[54,949,303],{"emptyLinePlaceholder":302},[54,951,952,955,958,960,962,965,967,969,971,973,975,978,980,982,985,988],{"class":56,"line":329},[54,953,954],{"class":417},"print",[54,956,957],{"class":276},"(Font(",[54,959,656],{"class":367},[54,961,312],{"class":272},[54,963,964],{"class":276},"to_argb((",[54,966,663],{"class":417},[54,968,358],{"class":276},[54,970,95],{"class":417},[54,972,358],{"class":276},[54,974,95],{"class":417},[54,976,977],{"class":276},"))).color.rgb, Font(",[54,979,656],{"class":367},[54,981,312],{"class":272},[54,983,984],{"class":276},"to_argb(",[54,986,987],{"class":64},"\"#1f4e79\"",[54,989,990],{"class":276},")).color.rgb)\n",[42,992,994],{"id":993},"case-3-the-error-appears-when-saving","Case 3 — the error appears when saving",[10,996,997,998,1001,1002,1004,1005,1008],{},"This is the confusing one. Assigning a string to a cell's ",[14,999,1000],{},"fill"," is accepted without complaint, and the ",[14,1003,216],{}," only appears at ",[14,1006,1007],{},"wb.save()",", with a traceback that runs through openpyxl's stylesheet writer and never mentions your code:",[23,1010,1012],{"className":263,"code":1011,"language":265,"meta":29,"style":29},"import traceback\n\nwb = Workbook()\nws = wb.active\nws[\"A1\"] = \"Total\"\nws[\"A1\"].fill = \"FFFF00\"          # accepted here...\ntry:\n    wb.save(\"report.xlsx\")         # ...fails here\nexcept TypeError as e:\n    frames = [f\"{f.filename.split('site-packages\u002F')[-1]}:{f.name}\" for f in traceback.extract_tb(e.__traceback__)]\n    print(\"TypeError:\", e)\n    print(\" -> \".join(frames[-4:]))\n",[14,1013,1014,1021,1025,1033,1041,1057,1075,1082,1096,1107,1170,1183],{"__ignoreMap":29},[54,1015,1016,1018],{"class":56,"line":57},[54,1017,280],{"class":272},[54,1019,1020],{"class":276}," traceback\n",[54,1022,1023],{"class":56,"line":286},[54,1024,303],{"emptyLinePlaceholder":302},[54,1026,1027,1029,1031],{"class":56,"line":299},[54,1028,309],{"class":276},[54,1030,312],{"class":272},[54,1032,315],{"class":276},[54,1034,1035,1037,1039],{"class":56,"line":306},[54,1036,321],{"class":276},[54,1038,312],{"class":272},[54,1040,326],{"class":276},[54,1042,1043,1046,1049,1052,1054],{"class":56,"line":318},[54,1044,1045],{"class":276},"ws[",[54,1047,1048],{"class":64},"\"A1\"",[54,1050,1051],{"class":276},"] ",[54,1053,312],{"class":272},[54,1055,1056],{"class":64}," \"Total\"\n",[54,1058,1059,1061,1063,1066,1068,1071],{"class":56,"line":329},[54,1060,1045],{"class":276},[54,1062,1048],{"class":64},[54,1064,1065],{"class":276},"].fill ",[54,1067,312],{"class":272},[54,1069,1070],{"class":64}," \"FFFF00\"",[54,1072,1074],{"class":1073},"s-wDw","          # accepted here...\n",[54,1076,1077,1080],{"class":56,"line":334},[54,1078,1079],{"class":272},"try",[54,1081,483],{"class":276},[54,1083,1084,1087,1090,1093],{"class":56,"line":349},[54,1085,1086],{"class":276},"    wb.save(",[54,1088,1089],{"class":64},"\"report.xlsx\"",[54,1091,1092],{"class":276},")         ",[54,1094,1095],{"class":1073},"# ...fails here\n",[54,1097,1098,1101,1103,1105],{"class":56,"line":379},[54,1099,1100],{"class":272},"except",[54,1102,532],{"class":417},[54,1104,535],{"class":272},[54,1106,538],{"class":276},[54,1108,1109,1112,1114,1117,1119,1121,1123,1126,1129,1132,1135,1138,1140,1142,1144,1146,1149,1151,1153,1156,1159,1161,1164,1167],{"class":56,"line":402},[54,1110,1111],{"class":276},"    frames ",[54,1113,312],{"class":272},[54,1115,1116],{"class":276}," [",[54,1118,501],{"class":272},[54,1120,504],{"class":64},[54,1122,508],{"class":507},[54,1124,1125],{"class":276},"f.filename.split(",[54,1127,1128],{"class":64},"'site-packages\u002F'",[54,1130,1131],{"class":276},")[",[54,1133,1134],{"class":272},"-",[54,1136,1137],{"class":417},"1",[54,1139,853],{"class":276},[54,1141,517],{"class":507},[54,1143,610],{"class":64},[54,1145,508],{"class":507},[54,1147,1148],{"class":276},"f.name",[54,1150,517],{"class":507},[54,1152,504],{"class":64},[54,1154,1155],{"class":272}," for",[54,1157,1158],{"class":276}," f ",[54,1160,343],{"class":272},[54,1162,1163],{"class":276}," traceback.extract_tb(e.",[54,1165,1166],{"class":417},"__traceback__",[54,1168,1169],{"class":276},")]\n",[54,1171,1172,1175,1177,1180],{"class":56,"line":440},[54,1173,1174],{"class":417},"    print",[54,1176,498],{"class":276},[54,1178,1179],{"class":64},"\"TypeError:\"",[54,1181,1182],{"class":276},", e)\n",[54,1184,1185,1187,1189,1192,1195,1197,1199],{"class":56,"line":471},[54,1186,1174],{"class":417},[54,1188,498],{"class":276},[54,1190,1191],{"class":64},"\" -> \"",[54,1193,1194],{"class":276},".join(frames[",[54,1196,1134],{"class":272},[54,1198,94],{"class":417},[54,1200,1201],{"class":276},":]))\n",[10,1203,1204,1205,1208,1209,1212,1213,358,1216,358,1219,358,1222,358,1225,1228],{},"When the traceback ends in ",[14,1206,1207],{},"write_stylesheet"," or elsewhere in ",[14,1210,1211],{},"openpyxl\u002Fwriter",", search your code for style assignments — ",[14,1214,1215],{},".fill =",[14,1217,1218],{},".border =",[14,1220,1221],{},".font =",[14,1223,1224],{},".alignment =",[14,1226,1227],{},".protection ="," — and check that each assigns a style object. The fix is the object, but there is a catch: correcting the cell in the same session is not enough. The bad value was already added to the workbook's table of fills, and the next save fails the same way:",[23,1230,1232],{"className":263,"code":1231,"language":265,"meta":29,"style":29},"ws[\"A1\"].fill = PatternFill(fill_type=\"solid\", fgColor=\"FFFF00\")\ntry:\n    wb.save(\"report.xlsx\")\nexcept TypeError as e:\n    print(\"still fails:\", e)\n",[14,1233,1234,1265,1271,1279,1289],{"__ignoreMap":29},[54,1235,1236,1238,1240,1242,1244,1247,1250,1252,1254,1256,1258,1260,1263],{"class":56,"line":57},[54,1237,1045],{"class":276},[54,1239,1048],{"class":64},[54,1241,1065],{"class":276},[54,1243,312],{"class":272},[54,1245,1246],{"class":276}," PatternFill(",[54,1248,1249],{"class":367},"fill_type",[54,1251,312],{"class":272},[54,1253,713],{"class":64},[54,1255,358],{"class":276},[54,1257,718],{"class":367},[54,1259,312],{"class":272},[54,1261,1262],{"class":64},"\"FFFF00\"",[54,1264,523],{"class":276},[54,1266,1267,1269],{"class":56,"line":286},[54,1268,1079],{"class":272},[54,1270,483],{"class":276},[54,1272,1273,1275,1277],{"class":56,"line":299},[54,1274,1086],{"class":276},[54,1276,1089],{"class":64},[54,1278,523],{"class":276},[54,1280,1281,1283,1285,1287],{"class":56,"line":306},[54,1282,1100],{"class":272},[54,1284,532],{"class":417},[54,1286,535],{"class":272},[54,1288,538],{"class":276},[54,1290,1291,1293,1295,1298],{"class":56,"line":318},[54,1292,1174],{"class":417},[54,1294,498],{"class":276},[54,1296,1297],{"class":64},"\"still fails:\"",[54,1299,1182],{"class":276},[10,1301,1302],{},"Fix the code and rebuild the workbook from the start, which in a script simply means running it again:",[23,1304,1306],{"className":263,"code":1305,"language":265,"meta":29,"style":29},"wb = Workbook()\nws = wb.active\nws[\"A1\"] = \"Total\"\nws[\"A1\"].fill = PatternFill(fill_type=\"solid\", fgColor=\"FFFF00\")\nwb.save(\"report.xlsx\")\nprint(\"saved\")\n",[14,1307,1308,1316,1324,1336,1364,1373],{"__ignoreMap":29},[54,1309,1310,1312,1314],{"class":56,"line":57},[54,1311,309],{"class":276},[54,1313,312],{"class":272},[54,1315,315],{"class":276},[54,1317,1318,1320,1322],{"class":56,"line":286},[54,1319,321],{"class":276},[54,1321,312],{"class":272},[54,1323,326],{"class":276},[54,1325,1326,1328,1330,1332,1334],{"class":56,"line":299},[54,1327,1045],{"class":276},[54,1329,1048],{"class":64},[54,1331,1051],{"class":276},[54,1333,312],{"class":272},[54,1335,1056],{"class":64},[54,1337,1338,1340,1342,1344,1346,1348,1350,1352,1354,1356,1358,1360,1362],{"class":56,"line":306},[54,1339,1045],{"class":276},[54,1341,1048],{"class":64},[54,1343,1065],{"class":276},[54,1345,312],{"class":272},[54,1347,1246],{"class":276},[54,1349,1249],{"class":367},[54,1351,312],{"class":272},[54,1353,713],{"class":64},[54,1355,358],{"class":276},[54,1357,718],{"class":367},[54,1359,312],{"class":272},[54,1361,1262],{"class":64},[54,1363,523],{"class":276},[54,1365,1366,1369,1371],{"class":56,"line":318},[54,1367,1368],{"class":276},"wb.save(",[54,1370,1089],{"class":64},[54,1372,523],{"class":276},[54,1374,1375,1377,1379,1382],{"class":56,"line":329},[54,1376,954],{"class":417},[54,1378,498],{"class":276},[54,1380,1381],{"class":64},"\"saved\"",[54,1383,523],{"class":276},[10,1385,1386,1387,1390],{},"In a large script, finding the bad assignment by reading code can take a while. Scan the workbook before saving instead: every style attribute should be a style object, and style objects have a ",[14,1388,1389],{},"tagname",", which plain strings and numbers do not:",[23,1392,1394],{"className":263,"code":1393,"language":265,"meta":29,"style":29},"def bad_styles(wb):\n    for sheet in wb.worksheets:\n        for row in sheet.iter_rows():\n            for cell in row:\n                for attr in (\"font\", \"fill\", \"border\", \"alignment\", \"protection\"):\n                    if getattr(getattr(cell, attr), \"tagname\", None) is None:\n                        yield sheet.title, cell.coordinate, attr, repr(getattr(cell, attr))\n\nwb = Workbook()\nws = wb.active\nws[\"B2\"], ws[\"C3\"] = \"x\", \"y\"\nws[\"B2\"].fill = \"FFFF00\"\nws[\"C3\"].border = \"thin\"\nprint(list(bad_styles(wb)))\n",[14,1395,1396,1406,1419,1432,1445,1482,1515,1533,1537,1545,1553,1578,1591,1605],{"__ignoreMap":29},[54,1397,1398,1400,1403],{"class":56,"line":57},[54,1399,872],{"class":272},[54,1401,1402],{"class":875}," bad_styles",[54,1404,1405],{"class":276},"(wb):\n",[54,1407,1408,1411,1414,1416],{"class":56,"line":286},[54,1409,1410],{"class":272},"    for",[54,1412,1413],{"class":276}," sheet ",[54,1415,343],{"class":272},[54,1417,1418],{"class":276}," wb.worksheets:\n",[54,1420,1421,1424,1427,1429],{"class":56,"line":299},[54,1422,1423],{"class":272},"        for",[54,1425,1426],{"class":276}," row ",[54,1428,343],{"class":272},[54,1430,1431],{"class":276}," sheet.iter_rows():\n",[54,1433,1434,1437,1440,1442],{"class":56,"line":306},[54,1435,1436],{"class":272},"            for",[54,1438,1439],{"class":276}," cell ",[54,1441,343],{"class":272},[54,1443,1444],{"class":276}," row:\n",[54,1446,1447,1450,1453,1455,1457,1460,1462,1465,1467,1470,1472,1475,1477,1480],{"class":56,"line":318},[54,1448,1449],{"class":272},"                for",[54,1451,1452],{"class":276}," attr ",[54,1454,343],{"class":272},[54,1456,791],{"class":276},[54,1458,1459],{"class":64},"\"font\"",[54,1461,358],{"class":276},[54,1463,1464],{"class":64},"\"fill\"",[54,1466,358],{"class":276},[54,1468,1469],{"class":64},"\"border\"",[54,1471,358],{"class":276},[54,1473,1474],{"class":64},"\"alignment\"",[54,1476,358],{"class":276},[54,1478,1479],{"class":64},"\"protection\"",[54,1481,896],{"class":276},[54,1483,1484,1487,1490,1492,1495,1498,1501,1503,1505,1507,1510,1513],{"class":56,"line":329},[54,1485,1486],{"class":272},"                    if",[54,1488,1489],{"class":417}," getattr",[54,1491,498],{"class":276},[54,1493,1494],{"class":417},"getattr",[54,1496,1497],{"class":276},"(cell, attr), ",[54,1499,1500],{"class":64},"\"tagname\"",[54,1502,358],{"class":276},[54,1504,466],{"class":417},[54,1506,800],{"class":276},[54,1508,1509],{"class":272},"is",[54,1511,1512],{"class":417}," None",[54,1514,483],{"class":276},[54,1516,1517,1520,1523,1526,1528,1530],{"class":56,"line":334},[54,1518,1519],{"class":272},"                        yield",[54,1521,1522],{"class":276}," sheet.title, cell.coordinate, attr, ",[54,1524,1525],{"class":417},"repr",[54,1527,498],{"class":276},[54,1529,1494],{"class":417},[54,1531,1532],{"class":276},"(cell, attr))\n",[54,1534,1535],{"class":56,"line":349},[54,1536,303],{"emptyLinePlaceholder":302},[54,1538,1539,1541,1543],{"class":56,"line":379},[54,1540,309],{"class":276},[54,1542,312],{"class":272},[54,1544,315],{"class":276},[54,1546,1547,1549,1551],{"class":56,"line":402},[54,1548,321],{"class":276},[54,1550,312],{"class":272},[54,1552,326],{"class":276},[54,1554,1555,1557,1560,1563,1566,1568,1570,1573,1575],{"class":56,"line":440},[54,1556,1045],{"class":276},[54,1558,1559],{"class":64},"\"B2\"",[54,1561,1562],{"class":276},"], ws[",[54,1564,1565],{"class":64},"\"C3\"",[54,1567,1051],{"class":276},[54,1569,312],{"class":272},[54,1571,1572],{"class":64}," \"x\"",[54,1574,358],{"class":276},[54,1576,1577],{"class":64},"\"y\"\n",[54,1579,1580,1582,1584,1586,1588],{"class":56,"line":471},[54,1581,1045],{"class":276},[54,1583,1559],{"class":64},[54,1585,1065],{"class":276},[54,1587,312],{"class":272},[54,1589,1590],{"class":64}," \"FFFF00\"\n",[54,1592,1593,1595,1597,1600,1602],{"class":56,"line":477},[54,1594,1045],{"class":276},[54,1596,1565],{"class":64},[54,1598,1599],{"class":276},"].border ",[54,1601,312],{"class":272},[54,1603,1604],{"class":64}," \"thin\"\n",[54,1606,1607,1609,1611,1614],{"class":56,"line":486},[54,1608,954],{"class":417},[54,1610,498],{"class":276},[54,1612,1613],{"class":417},"list",[54,1615,1616],{"class":276},"(bad_styles(wb)))\n",[10,1618,1619,1620,1623],{},"It names the sheet, the cell and the attribute, which is everything the save-time traceback leaves out. It cannot catch Case 4 below, where the wrong value has already been turned into a real, but wrong, style object. Run it in tests or just before ",[14,1621,1622],{},"save()"," while debugging.",[73,1625,82,1631,82,1634,82,1637,82,1642,82,1648,82,1653,82,1657,82,1661,82,1665,82,1670,82,1672,82,1675,82,1678,82,1682,82,1684,82,1686,82,1689,82,1693,82,1695,82,1699,82,1702,82,1706,82,1708],{"viewBox":1626,"role":76,"ariaLabelledBy":1627,"xmlns":80,"style":1630},"240 0 280 172",[1628,1629],"te-where-t","te-where-d","width:100%;max-width:280px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[84,1632,1633],{"id":1628},"When each mistake is caught",[88,1635,1636],{"id":1629},"A table of common wrong assignments and when openpyxl reports them. Font size given as a word fails immediately. A colour given as a tuple fails immediately. A fill given as a string is accepted and fails at save. A font given as a string is accepted and silently becomes a font named bold.",[92,1638],{"x":1639,"y":95,"width":1640,"height":1641,"fill":98},"240","280","172",[92,1643],{"x":1644,"y":102,"width":1645,"height":1646,"rx":95,"fill":149,"stroke":140,"style":1647},"256.4","153.7","28.0","stroke-width:1.5px",[28,1649,125],{"x":1650,"y":1651,"style":1652},"333.3","35.0","font-size:11px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[92,1654],{"x":1655,"y":102,"width":1656,"height":1646,"rx":95,"fill":149,"stroke":140,"style":1647},"410.2","93.4",[28,1658,1660],{"x":1659,"y":1651,"style":1652},"456.9","Reported",[92,1662],{"x":1644,"y":1663,"width":1645,"height":1646,"rx":95,"fill":98,"stroke":107,"style":1664},"44.0","stroke-width:1px",[28,1666,1669],{"x":1650,"y":1667,"style":1668},"63.0","font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Font(size='large')",[92,1671],{"x":1655,"y":1663,"width":1656,"height":1646,"rx":95,"fill":98,"stroke":107,"style":1664},[28,1673,1674],{"x":1659,"y":1667,"style":1668},"immediately",[92,1676],{"x":1644,"y":1677,"width":1645,"height":1646,"rx":95,"fill":98,"stroke":107,"style":1664},"72.0",[28,1679,1681],{"x":1650,"y":1680,"style":1668},"91.0","Font(color=(255, 0, 0))",[92,1683],{"x":1655,"y":1677,"width":1656,"height":1646,"rx":95,"fill":98,"stroke":107,"style":1664},[28,1685,1674],{"x":1659,"y":1680,"style":1668},[92,1687],{"x":1644,"y":1688,"width":1645,"height":1646,"rx":95,"fill":98,"stroke":107,"style":1664},"100.0",[28,1690,1692],{"x":1650,"y":1691,"style":1668},"119.0","cell.fill = 'FFFF00'",[92,1694],{"x":1655,"y":1688,"width":1656,"height":1646,"rx":95,"fill":230,"stroke":231,"style":1647},[28,1696,1698],{"x":1659,"y":1691,"style":1697},"font-size:11px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","at save",[92,1700],{"x":1644,"y":1701,"width":1645,"height":1646,"rx":95,"fill":98,"stroke":107,"style":1664},"128.0",[28,1703,1705],{"x":1650,"y":1704,"style":1668},"147.0","cell.font = 'bold'",[92,1707],{"x":1655,"y":1701,"width":1656,"height":1646,"rx":95,"fill":200,"stroke":201,"style":1647},[28,1709,1711],{"x":1659,"y":1704,"style":1710},"font-size:11px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","never",[73,1713,82,1719,82,1722,82,1725,82,1730,82,1737,82,1744,82,1748,82,1751,82,1753,82,1759,82,1763,82,1767,82,1770,82,1775,82,1779],{"viewBox":1714,"role":76,"ariaLabelledBy":1715,"xmlns":80,"style":1718},"64 0 632 331",[1716,1717],"te-poison-t","te-poison-d","width:100%;max-width:632px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[84,1720,1721],{"id":1716},"Why fixing the cell is not enough",[88,1723,1724],{"id":1717},"Three layers. The cell refers to an entry in the workbook's style table. The bad string was added to that table when it was assigned. Correcting the cell adds a good entry but leaves the bad one in the table, so the stylesheet still fails to write.",[92,1726],{"x":1727,"y":95,"width":1728,"height":1729,"fill":98},"64","632","331",[92,1731],{"x":1732,"y":102,"width":1733,"height":1734,"rx":105,"fill":1735,"stroke":1736,"style":108},"80.0","600.0","93.0","#d9f4f1","var(--teal,#0f9488)",[110,1738,1740],{"transform":1739},"translate(368.0,29.0) scale(1.000)",[114,1741],{"d":1742,"fill":117,"stroke":1743,"style":119},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16","var(--teal-ink,#0b6157)",[28,1745,1747],{"x":185,"y":123,"style":1746},"font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Cell A1",[28,1749,1750],{"x":185,"y":128,"style":129},"now points to a PatternFill",[92,1752],{"x":1732,"y":1691,"width":1733,"height":1734,"rx":105,"fill":230,"stroke":231,"style":108},[110,1754,1756],{"transform":1755},"translate(368.0,132.0) scale(1.000)",[114,1757],{"d":1758,"fill":117,"stroke":238,"style":119},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14",[28,1760,1762],{"x":185,"y":1761,"style":242},"178.5","Workbook fill table",[28,1764,1766],{"x":185,"y":1765,"style":129},"198.0","[default, 'FFFF00', PatternFill]",[92,1768],{"x":1732,"y":1769,"width":1733,"height":1734,"rx":105,"fill":200,"stroke":201,"style":108},"222.0",[110,1771,1773],{"transform":1772},"translate(368.0,235.0) scale(1.000)",[114,1774],{"d":207,"fill":117,"stroke":208,"style":119},[28,1776,1778],{"x":185,"y":1777,"style":212},"281.5","Stylesheet writer",[28,1780,1782],{"x":185,"y":1781,"style":129},"301.0","fails on the string entry",[42,1784,1786],{"id":1785},"case-4-the-mistake-that-never-errors","Case 4 — the mistake that never errors",[10,1788,1789,1790,1793,1794,1798],{},"Worse than a late error is none at all. ",[14,1791,1792],{},"cell.font = \"bold\""," is accepted ",[1795,1796,1797],"em",{},"and"," saved, because the string is quietly converted into a font whose name is \"bold\". The text is not bold; the file just asks for a font that does not exist:",[23,1800,1802],{"className":263,"code":1801,"language":265,"meta":29,"style":29},"from openpyxl import load_workbook\n\nwb = Workbook()\nws = wb.active\nws[\"A1\"] = \"Heading\"\nws[\"A1\"].font = \"bold\"\nwb.save(\"silent.xlsx\")\nfont = load_workbook(\"silent.xlsx\").active[\"A1\"].font\nprint(f\"name={font.name!r} bold={font.b}\")\n",[14,1803,1804,1815,1819,1827,1835,1848,1862,1871,1891],{"__ignoreMap":29},[54,1805,1806,1808,1810,1812],{"class":56,"line":57},[54,1807,273],{"class":272},[54,1809,277],{"class":276},[54,1811,280],{"class":272},[54,1813,1814],{"class":276}," load_workbook\n",[54,1816,1817],{"class":56,"line":286},[54,1818,303],{"emptyLinePlaceholder":302},[54,1820,1821,1823,1825],{"class":56,"line":299},[54,1822,309],{"class":276},[54,1824,312],{"class":272},[54,1826,315],{"class":276},[54,1828,1829,1831,1833],{"class":56,"line":306},[54,1830,321],{"class":276},[54,1832,312],{"class":272},[54,1834,326],{"class":276},[54,1836,1837,1839,1841,1843,1845],{"class":56,"line":318},[54,1838,1045],{"class":276},[54,1840,1048],{"class":64},[54,1842,1051],{"class":276},[54,1844,312],{"class":272},[54,1846,1847],{"class":64}," \"Heading\"\n",[54,1849,1850,1852,1854,1857,1859],{"class":56,"line":329},[54,1851,1045],{"class":276},[54,1853,1048],{"class":64},[54,1855,1856],{"class":276},"].font ",[54,1858,312],{"class":272},[54,1860,1861],{"class":64}," \"bold\"\n",[54,1863,1864,1866,1869],{"class":56,"line":334},[54,1865,1368],{"class":276},[54,1867,1868],{"class":64},"\"silent.xlsx\"",[54,1870,523],{"class":276},[54,1872,1873,1876,1878,1881,1883,1886,1888],{"class":56,"line":349},[54,1874,1875],{"class":276},"font ",[54,1877,312],{"class":272},[54,1879,1880],{"class":276}," load_workbook(",[54,1882,1868],{"class":64},[54,1884,1885],{"class":276},").active[",[54,1887,1048],{"class":64},[54,1889,1890],{"class":276},"].font\n",[54,1892,1893,1895,1897,1899,1902,1904,1907,1910,1912,1915,1917,1920,1922,1924],{"class":56,"line":379},[54,1894,954],{"class":417},[54,1896,498],{"class":276},[54,1898,501],{"class":272},[54,1900,1901],{"class":64},"\"name=",[54,1903,508],{"class":507},[54,1905,1906],{"class":276},"font.name",[54,1908,1909],{"class":272},"!r",[54,1911,517],{"class":507},[54,1913,1914],{"class":64}," bold=",[54,1916,508],{"class":507},[54,1918,1919],{"class":276},"font.b",[54,1921,517],{"class":507},[54,1923,504],{"class":64},[54,1925,523],{"class":276},[10,1927,1928,1929,358,1932,358,1935,358,1938,1941,1942,1945,1946,40],{},"Style attributes take style objects: ",[14,1930,1931],{},"Font(bold=True)",[14,1933,1934],{},"PatternFill(...)",[14,1936,1937],{},"Border(...)",[14,1939,1940],{},"Alignment(...)",". A quick way to catch these is to assert on the style you meant in a test, for example ",[14,1943,1944],{},"assert ws[\"A1\"].font.b",", as shown in ",[36,1947,1949],{"href":1948},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Ftest-excel-output-with-pytest\u002F","Test Excel Output with pytest",[42,1951,1953],{"id":1952},"case-5-chart-attributes","Case 5 — chart attributes",[10,1955,1956,1957,1960,1961],{},"Chart titles accept a string, which openpyxl converts to a ",[14,1958,1959],{},"Title"," object, but not a number; that surfaces as a \"should be ",[1962,1963,1964,1965,1968],"class",{"title":29},"\" error when a year or ID is used as a title. Chart ",[14,1966,1967],{},"style"," is a style number from 1 to 48, not a name:",[23,1970,1972],{"className":263,"code":1971,"language":265,"meta":29,"style":29},"from openpyxl.chart import BarChart\n\nchart = BarChart()\nfor label, action in [\n    (\"title = 'Sales 2026'\", lambda: setattr(chart, \"title\", \"Sales 2026\")),\n    (\"title = 2026\", lambda: setattr(chart, \"title\", 2026)),\n    (\"style = 'modern'\", lambda: setattr(chart, \"style\", \"modern\")),\n    (\"style = 10\", lambda: setattr(chart, \"style\", 10)),\n]:\n    try:\n        action()\n        print(f\"{label:22} accepted\")\n    except TypeError as e:\n        print(f\"{label:22} TypeError: {str(e)[:80]}\")\n",[14,1973,1974,1986,1990,2000,2010,2038,2064,2091,2117,2121,2127,2131,2153,2163],{"__ignoreMap":29},[54,1975,1976,1978,1981,1983],{"class":56,"line":57},[54,1977,273],{"class":272},[54,1979,1980],{"class":276}," openpyxl.chart ",[54,1982,280],{"class":272},[54,1984,1985],{"class":276}," BarChart\n",[54,1987,1988],{"class":56,"line":286},[54,1989,303],{"emptyLinePlaceholder":302},[54,1991,1992,1995,1997],{"class":56,"line":299},[54,1993,1994],{"class":276},"chart ",[54,1996,312],{"class":272},[54,1998,1999],{"class":276}," BarChart()\n",[54,2001,2002,2004,2006,2008],{"class":56,"line":306},[54,2003,337],{"class":272},[54,2005,340],{"class":276},[54,2007,343],{"class":272},[54,2009,346],{"class":276},[54,2011,2012,2014,2017,2019,2021,2023,2025,2028,2031,2033,2036],{"class":56,"line":318},[54,2013,352],{"class":276},[54,2015,2016],{"class":64},"\"title = 'Sales 2026'\"",[54,2018,358],{"class":276},[54,2020,361],{"class":272},[54,2022,414],{"class":276},[54,2024,418],{"class":417},[54,2026,2027],{"class":276},"(chart, ",[54,2029,2030],{"class":64},"\"title\"",[54,2032,358],{"class":276},[54,2034,2035],{"class":64},"\"Sales 2026\"",[54,2037,376],{"class":276},[54,2039,2040,2042,2045,2047,2049,2051,2053,2055,2057,2059,2062],{"class":56,"line":329},[54,2041,352],{"class":276},[54,2043,2044],{"class":64},"\"title = 2026\"",[54,2046,358],{"class":276},[54,2048,361],{"class":272},[54,2050,414],{"class":276},[54,2052,418],{"class":417},[54,2054,2027],{"class":276},[54,2056,2030],{"class":64},[54,2058,358],{"class":276},[54,2060,2061],{"class":417},"2026",[54,2063,376],{"class":276},[54,2065,2066,2068,2071,2073,2075,2077,2079,2081,2084,2086,2089],{"class":56,"line":334},[54,2067,352],{"class":276},[54,2069,2070],{"class":64},"\"style = 'modern'\"",[54,2072,358],{"class":276},[54,2074,361],{"class":272},[54,2076,414],{"class":276},[54,2078,418],{"class":417},[54,2080,2027],{"class":276},[54,2082,2083],{"class":64},"\"style\"",[54,2085,358],{"class":276},[54,2087,2088],{"class":64},"\"modern\"",[54,2090,376],{"class":276},[54,2092,2093,2095,2098,2100,2102,2104,2106,2108,2110,2112,2115],{"class":56,"line":349},[54,2094,352],{"class":276},[54,2096,2097],{"class":64},"\"style = 10\"",[54,2099,358],{"class":276},[54,2101,361],{"class":272},[54,2103,414],{"class":276},[54,2105,418],{"class":417},[54,2107,2027],{"class":276},[54,2109,2083],{"class":64},[54,2111,358],{"class":276},[54,2113,2114],{"class":417},"10",[54,2116,376],{"class":276},[54,2118,2119],{"class":56,"line":379},[54,2120,474],{"class":276},[54,2122,2123,2125],{"class":56,"line":402},[54,2124,480],{"class":272},[54,2126,483],{"class":276},[54,2128,2129],{"class":56,"line":440},[54,2130,489],{"class":276},[54,2132,2133,2135,2137,2139,2141,2143,2145,2147,2149,2151],{"class":56,"line":471},[54,2134,495],{"class":417},[54,2136,498],{"class":276},[54,2138,501],{"class":272},[54,2140,504],{"class":64},[54,2142,508],{"class":507},[54,2144,511],{"class":276},[54,2146,514],{"class":272},[54,2148,517],{"class":507},[54,2150,520],{"class":64},[54,2152,523],{"class":276},[54,2154,2155,2157,2159,2161],{"class":56,"line":477},[54,2156,529],{"class":272},[54,2158,532],{"class":417},[54,2160,535],{"class":272},[54,2162,538],{"class":276},[54,2164,2165,2167,2169,2171,2173,2175,2177,2179,2181,2183,2185,2187,2189,2192,2194,2196,2198],{"class":56,"line":486},[54,2166,495],{"class":417},[54,2168,498],{"class":276},[54,2170,501],{"class":272},[54,2172,504],{"class":64},[54,2174,508],{"class":507},[54,2176,511],{"class":276},[54,2178,514],{"class":272},[54,2180,517],{"class":507},[54,2182,560],{"class":64},[54,2184,508],{"class":507},[54,2186,844],{"class":417},[54,2188,847],{"class":276},[54,2190,2191],{"class":417},"80",[54,2193,853],{"class":276},[54,2195,517],{"class":507},[54,2197,504],{"class":64},[54,2199,523],{"class":276},[10,2201,2202,2203,2206,2207,40],{},"Convert labels with ",[14,2204,2205],{},"str()"," when they come from data: ",[14,2208,2209],{},"chart.title = str(year)",[42,2211,2213],{"id":2212},"values-from-pandas-and-numpy","Values from pandas and NumPy",[10,2215,2216,2217,2219,2220,2222,2223,610],{},"Settings often arrive from a DataFrame, as NumPy numbers rather than Python ones. Numeric attributes accept them, because ",[14,2218,259],{}," converts them. Cell values accept NumPy scalars too. What fails is a container: a list or dict read from JSON config and assigned as a cell value raises a different error, a ",[14,2221,609],{},", not a ",[14,2224,216],{},[23,2226,2228],{"className":263,"code":2227,"language":265,"meta":29,"style":29},"import numpy as np\n\nwb = Workbook()\nws = wb.active\nws.row_dimensions[1].height = np.float32(24)\nws[\"A1\"] = np.int64(5)\nprint(\"NumPy values accepted:\", ws.row_dimensions[1].height, ws[\"A1\"].value)\ntry:\n    ws[\"A2\"] = [\"North\", \"South\"]\nexcept ValueError as e:\n    print(\"ValueError:\", e)\n",[14,2229,2230,2242,2246,2254,2262,2282,2300,2322,2328,2353,2364],{"__ignoreMap":29},[54,2231,2232,2234,2237,2239],{"class":56,"line":57},[54,2233,280],{"class":272},[54,2235,2236],{"class":276}," numpy ",[54,2238,803],{"class":272},[54,2240,2241],{"class":276}," np\n",[54,2243,2244],{"class":56,"line":286},[54,2245,303],{"emptyLinePlaceholder":302},[54,2247,2248,2250,2252],{"class":56,"line":299},[54,2249,309],{"class":276},[54,2251,312],{"class":272},[54,2253,315],{"class":276},[54,2255,2256,2258,2260],{"class":56,"line":306},[54,2257,321],{"class":276},[54,2259,312],{"class":272},[54,2261,326],{"class":276},[54,2263,2264,2267,2269,2272,2274,2277,2280],{"class":56,"line":318},[54,2265,2266],{"class":276},"ws.row_dimensions[",[54,2268,1137],{"class":417},[54,2270,2271],{"class":276},"].height ",[54,2273,312],{"class":272},[54,2275,2276],{"class":276}," np.float32(",[54,2278,2279],{"class":417},"24",[54,2281,523],{"class":276},[54,2283,2284,2286,2288,2290,2292,2295,2298],{"class":56,"line":329},[54,2285,1045],{"class":276},[54,2287,1048],{"class":64},[54,2289,1051],{"class":276},[54,2291,312],{"class":272},[54,2293,2294],{"class":276}," np.int64(",[54,2296,2297],{"class":417},"5",[54,2299,523],{"class":276},[54,2301,2302,2304,2306,2309,2312,2314,2317,2319],{"class":56,"line":334},[54,2303,954],{"class":417},[54,2305,498],{"class":276},[54,2307,2308],{"class":64},"\"NumPy values accepted:\"",[54,2310,2311],{"class":276},", ws.row_dimensions[",[54,2313,1137],{"class":417},[54,2315,2316],{"class":276},"].height, ws[",[54,2318,1048],{"class":64},[54,2320,2321],{"class":276},"].value)\n",[54,2323,2324,2326],{"class":56,"line":349},[54,2325,1079],{"class":272},[54,2327,483],{"class":276},[54,2329,2330,2333,2336,2338,2340,2342,2345,2347,2350],{"class":56,"line":379},[54,2331,2332],{"class":276},"    ws[",[54,2334,2335],{"class":64},"\"A2\"",[54,2337,1051],{"class":276},[54,2339,312],{"class":272},[54,2341,1116],{"class":276},[54,2343,2344],{"class":64},"\"North\"",[54,2346,358],{"class":276},[54,2348,2349],{"class":64},"\"South\"",[54,2351,2352],{"class":276},"]\n",[54,2354,2355,2357,2360,2362],{"class":56,"line":402},[54,2356,1100],{"class":272},[54,2358,2359],{"class":417}," ValueError",[54,2361,535],{"class":272},[54,2363,538],{"class":276},[54,2365,2366,2368,2370,2373],{"class":56,"line":440},[54,2367,1174],{"class":417},[54,2369,498],{"class":276},[54,2371,2372],{"class":64},"\"ValueError:\"",[54,2374,1182],{"class":276},[10,2376,2377],{},"That one is covered in its own page, linked below; the fix is to write one value per cell or join the list into a string.",[42,2379,2381],{"id":2380},"common-pitfalls","Common pitfalls",[2383,2384,2385,2393,2402,2415,2424],"ul",{},[2386,2387,2388,2392],"li",{},[2389,2390,2391],"strong",{},"Reading only the last line."," The class in the message tells you the kind of attribute; the traceback line above it tells you which assignment.",[2386,2394,2395,2398,2399,2401],{},[2389,2396,2397],{},"Tracebacks ending in openpyxl's writer."," The cause is an earlier style assignment of the wrong type; search for ",[14,2400,1215],{}," and friends.",[2386,2403,2404,2407,2408,2410,2411,2414],{},[2389,2405,2406],{},"CSS colours."," Strip the ",[14,2409,605],{},"; openpyxl wants aRGB hex, not ",[14,2412,2413],{},"#RRGGBB"," or colour names.",[2386,2416,2417,2420,2421,2423],{},[2389,2418,2419],{},"Strings for style objects."," ",[14,2422,1792],{}," saves without error and does nothing useful.",[2386,2425,2426,2429],{},[2389,2427,2428],{},"Config values as strings."," Numeric strings convert, words and empty values do not; validate settings up front.",[42,2431,2433],{"id":2432},"conclusion","Conclusion",[10,2435,2436,2437,2439,2440,2443,2444,2446,2447,358,2449,2452,2453,2455,2456,2458,2459,2461],{},"The class named in openpyxl's ",[14,2438,216],{}," is the type the attribute expects: ",[14,2441,2442],{},"float"," for sizes, widths and chart styles, ",[14,2445,20],{}," for colours, ",[14,2448,16],{},[14,2450,2451],{},"Font"," and the other style classes for cell formatting, ",[14,2454,1959],{}," for chart titles. Pass that type — style objects rather than strings, aRGB hex strings rather than tuples or ",[14,2457,605],{}," colours, numbers rather than words. When the traceback ends inside openpyxl's writer, the cause is an earlier style assignment; and remember that ",[14,2460,1792],{}," fails silently, so check styles in tests.",[42,2463,2465],{"id":2464},"frequently-asked-questions","Frequently asked questions",[10,2467,2468,2471],{},[2389,2469,2470],{},"What does \"TypeError: expected \u003Cclass 'float'>\" mean in openpyxl?","\nA numeric attribute such as a font size, column width, row height or chart style received a value that float() cannot convert, such as a word or None. Pass a number.",[10,2473,2474,2477],{},[2389,2475,2476],{},"How do I set a colour in openpyxl?","\nUse an aRGB hex string without the hash, such as \"FF0000\" or \"FFFF0000\", or a Color object. RGB tuples and CSS names are rejected.",[10,2479,2480,2483],{},[2389,2481,2482],{},"Why does openpyxl raise TypeError only when I save?","\nSome style assignments, such as a string assigned to cell.fill, are stored without checking and converted when the stylesheet is written. Look for style attributes assigned a string or other plain value.",[10,2485,2486,2489],{},[2389,2487,2488],{},"Why is my text not bold after cell.font = \"bold\"?","\nThe string is treated as a font name, so the cell gets a font called bold. Use cell.font = Font(bold=True).",[42,2491,2493],{"id":2492},"related","Related",[2383,2495,2496,2502,2509,2516,2521],{},[2386,2497,2498,2499,2501],{},"Up one level: ",[36,2500,39],{"href":38}," — the other common errors.",[2386,2503,2504,2508],{},[36,2505,2507],{"href":2506},"\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"," — when a file saves but Excel complains.",[2386,2510,2511,2515],{},[36,2512,2514],{"href":2513},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-cannot-convert-to-excel-valueerror\u002F","Fix \"ValueError: Cannot convert to Excel\" in openpyxl"," — the cell value equivalent.",[2386,2517,2518,2520],{},[36,2519,1949],{"href":1948}," — catching silent style mistakes.",[2386,2522,2523,2527],{},[36,2524,2526],{"href":2525},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-max-row-counting-empty-rows\u002F","Fix openpyxl max_row Counting Empty Rows"," — another openpyxl surprise.",[1967,2529,2530],{},"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 .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":29,"searchDepth":286,"depth":286,"links":2532},[2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543],{"id":44,"depth":286,"text":45},{"id":252,"depth":286,"text":253},{"id":584,"depth":286,"text":585},{"id":993,"depth":286,"text":994},{"id":1785,"depth":286,"text":1786},{"id":1952,"depth":286,"text":1953},{"id":2212,"depth":286,"text":2213},{"id":2380,"depth":286,"text":2381},{"id":2432,"depth":286,"text":2433},{"id":2464,"depth":286,"text":2465},{"id":2492,"depth":286,"text":2493},"2026-09-29","openpyxl checks the type of every style, chart and dimension attribute, and raises \"TypeError: expected \u003Cclass 'float'>\" or \"expected \u003Cclass 'openpyxl.styles.fills.Fill'>\" when it gets the wrong kind of value. Read the class name, find the assignment, and pass the right object — including the case where the error only appears at save time, far from the line that caused it.","md",[2548,2550,2552,2554],{"q":2470,"a":2549},"A numeric attribute such as a font size, column width, row height or chart style received a value that float() cannot convert, such as a word or None. Pass a number.",{"q":2476,"a":2551},"Use an aRGB hex string without the hash, such as \"FF0000\" or \"FFFF0000\", or a Color object. RGB tuples and CSS names are rejected.",{"q":2482,"a":2553},"Some style assignments, such as a string assigned to cell.fill, are stored without checking and converted when the stylesheet is written. Look for style attributes assigned a string or other plain value.",{"q":2488,"a":2555},"The string is treated as a font name, so the cell gets a font called bold. Use cell.font = Font(bold=True).","fix openpyxl typeerror expected class",null,{"breadcrumb":2559},[2560,2563,2566],{"name":2561,"item":2562},"Home","\u002F",{"name":2564,"item":2565},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":39,"item":38},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-typeerror-expected-class",{"title":2569,"description":2570},"Fix openpyxl TypeError: expected \u003Cclass 'float'> \u002F Fill \u002F Color","Why openpyxl raises TypeError expected \u003Cclass ...> and 'should be \u003Cclass Color> but value is tuple': wrong types for Font, PatternFill, colours, column widths and chart titles, and fill errors that only surface on save.","fix-openpyxl-typeerror-expected-class","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-typeerror-expected-class\u002Findex",[2574,2575],"troubleshooting","openpyxl","how-to","oenuNffhiYpj4K9KBQ3-6nstMbxwFuVlyp5Q7HdH1uw",[2579,2582],{"title":2526,"path":2580,"stem":2581,"children":-1},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-max-row-counting-empty-rows","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-max-row-counting-empty-rows\u002Findex",{"title":2583,"path":2584,"stem":2585,"children":-1},"Fix openpyxl \"Value must be one of\" and \"Max value is\" Errors","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-value-must-be-one-of-errors","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-value-must-be-one-of-errors\u002Findex",[2587,2589],{"path":2588,"title":2564},"\u002Fgetting-started-with-python-excel-automation",{"path":2590,"title":39},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors",[],[2593,2597,2600,2603,2606,2609],{"path":2594,"title":2595,"kind":2596},"\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":2598,"title":2599,"kind":2576},"\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":2601,"title":2602,"kind":2596},"\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":2604,"title":2605,"kind":2576},"\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":2607,"title":2608,"kind":2576},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002Fhandle-microsoft-graph-throttling-for-excel","Handle Microsoft Graph Throttling in Excel Automation",{"path":2610,"title":2611,"kind":2612},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation","Error Handling and Logging in Excel Automation","guide",1790972067296]