[{"data":1,"prerenderedAt":2428},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-name-error-for-new-excel-functions-written-by-python":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-name-error-for-new-excel-functions-written-by-python":2393,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-name-error-for-new-excel-functions-written-by-python":2402,"children:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-name-error-for-new-excel-functions-written-by-python":2407,"related:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-name-error-for-new-excel-functions-written-by-python":2408},{"id":4,"title":5,"body":6,"dateModified":2358,"datePublished":2358,"description":2359,"extension":2360,"faq":2361,"keyword":2370,"kind":2371,"meta":2372,"navigation":363,"path":2381,"seo":2382,"slug":2385,"stem":2386,"topics":2387,"type":2391,"__hash__":2392},"docs\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-name-error-for-new-excel-functions-written-by-python\u002Findex.md","Fix #NAME? in Formulas Written from Python (XLOOKUP, TEXTJOIN, IFS)",{"type":7,"value":8,"toc":2346},"minimark",[9,13,24,43,52,191,196,221,279,283,286,493,575,587,699,703,710,938,963,967,970,1128,1135,1257,1271,1364,1379,1401,1405,1412,2049,2067,2198,2202,2252,2256,2263,2267,2281,2285,2291,2297,2303,2309,2313,2342],[10,11,12],"p",{},"A script writes a formula that works perfectly when typed into Excel:",[14,15,21],"pre",{"className":16,"code":18,"language":19,"meta":20},[17],"language-text","ws[\"D2\"] = '=XLOOKUP(A2, Prices!A:A, Prices!B:B)'\n","text","",[22,23,18],"code",{"__ignoreMap":20},[10,25,26,27,30,31,34,35,38,39,42],{},"and the cell shows ",[22,28,29],{},"#NAME?"," when the workbook is opened. The tell-tale sign is that clicking into the cell and pressing Enter fixes it. Nothing is wrong with the formula; what is wrong is how it is stored. Functions added to Excel after the original ",[22,32,33],{},".xlsx"," specification are saved in the file with an ",[22,36,37],{},"_xlfn."," prefix, and openpyxl writes exactly the text you give it. The spreadsheet reads a function called plain ",[22,40,41],{},"XLOOKUP",", does not recognise it as the new function, and reports an unknown name.",[10,44,45,46,51],{},"The same error has a handful of other causes that also come up only when formulas are generated rather than typed. This page, part of ",[47,48,50],"a",{"href":49},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002F","Troubleshooting Common Python Excel Errors",", covers all of them and ends with a linter that checks every formula before the workbook is saved. The results below were checked by recalculating the files in LibreOffice, which applies the same rule.",[53,54,62,63,62,67,62,71,62,79,62,89,62,100,62,106,62,113,62,119,62,125,62,129,62,134,62,138,62,145,62,150,62,157,62,162,62,166,62,170,62,175,62,178,62,183,62,186],"svg",{"viewBox":55,"role":56,"ariaLabelledBy":57,"xmlns":60,"style":61},"4 0 752 207","img",[58,59],"nme-prefix-t","nme-prefix-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  ",[64,65,66],"title",{"id":58},"The same function stored two ways",[68,69,70],"desc",{"id":59},"Left: the formula stored as =XLOOKUP(...) without a prefix is not recognised, and the cell shows #NAME?. Right: stored as =_xlfn.XLOOKUP(...), the function is recognised, the prefix is hidden from users, and the cell shows the looked-up value.",[72,73],"rect",{"x":74,"y":75,"width":76,"height":77,"fill":78},"4","0","752","207","#ffffff",[72,80],{"x":81,"y":82,"width":83,"height":84,"rx":85,"fill":86,"stroke":87,"style":88},"20.0","16.0","351.0","175.0","14","#fee8f2","var(--accent,#f43f8f)","stroke-width:2px",[90,91,93],"g",{"transform":92},"translate(182.5,29.0) scale(1.083)",[94,95],"path",{"d":96,"fill":97,"stroke":98,"style":99},"M6 6l12 12 M18 6L6 18","none","var(--accent-ink,#be185d)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[19,101,105],{"x":102,"y":103,"style":104},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Stored as =XLOOKUP(…)",[107,108],"line",{"x1":109,"y1":110,"x2":111,"y2":110,"stroke":87,"style":112},"36.0","91.0","355.0","stroke-width:1px",[19,114,118],{"x":115,"y":116,"style":117},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","not recognised on load",[90,120,122],{"transform":121},"translate(38.5,99.5) scale(0.625)",[94,123],{"d":96,"fill":97,"stroke":87,"style":124},"stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[19,126,128],{"x":115,"y":127,"style":117},"137.0","cell shows #NAME?",[90,130,132],{"transform":131},"translate(38.5,125.5) scale(0.625)",[94,133],{"d":96,"fill":97,"stroke":87,"style":124},[19,135,137],{"x":115,"y":136,"style":117},"163.0","re-entering the cell \"fixes\" it",[90,139,141],{"transform":140},"translate(38.5,151.5) scale(0.625)",[94,142],{"d":143,"fill":97,"stroke":144,"style":124},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold,#b4740a)",[72,146],{"x":147,"y":82,"width":83,"height":84,"rx":85,"fill":148,"stroke":149,"style":88},"389.0","#d9f4f1","var(--teal,#0f9488)",[90,151,153],{"transform":152},"translate(551.5,29.0) scale(1.083)",[94,154],{"d":155,"fill":97,"stroke":156,"style":99},"M5 12.5l4.5 4.5L19 7","var(--teal-ink,#0b6157)",[19,158,161],{"x":159,"y":103,"style":160},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Stored as =_xlfn.XLOOKUP(…)",[107,163],{"x1":164,"y1":110,"x2":165,"y2":110,"stroke":149,"style":112},"405.0","724.0",[19,167,169],{"x":168,"y":116,"style":117},"429.0","recognised as the new function",[90,171,173],{"transform":172},"translate(407.5,99.5) scale(0.625)",[94,174],{"d":155,"fill":97,"stroke":149,"style":124},[19,176,177],{"x":168,"y":127,"style":117},"users see =XLOOKUP(…)",[90,179,181],{"transform":180},"translate(407.5,125.5) scale(0.625)",[94,182],{"d":155,"fill":97,"stroke":149,"style":124},[19,184,185],{"x":168,"y":136,"style":117},"calculates on open",[90,187,189],{"transform":188},"translate(407.5,151.5) scale(0.625)",[94,190],{"d":155,"fill":97,"stroke":149,"style":124},[192,193,195],"h2",{"id":194},"prerequisites","Prerequisites",[14,197,201],{"className":198,"code":199,"language":200,"meta":20,"style":20},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl xlsxwriter\n","bash",[22,202,203],{"__ignoreMap":20},[204,205,207,211,215,218],"span",{"class":107,"line":206},1,[204,208,210],{"class":209},"sMTad","pip",[204,212,214],{"class":213},"srMev"," install",[204,216,217],{"class":213}," openpyxl",[204,219,220],{"class":213}," xlsxwriter\n",[14,222,226],{"className":223,"code":224,"language":225,"meta":20,"style":20},"language-python shiki shiki-themes github-light github-dark-high-contrast","import re\nfrom openpyxl import Workbook, load_workbook\nfrom openpyxl.utils import FORMULAE\nfrom openpyxl.workbook.defined_name import DefinedName\n","python",[22,227,228,238,252,266],{"__ignoreMap":20},[204,229,230,234],{"class":107,"line":206},[204,231,233],{"class":232},"s-kum","import",[204,235,237],{"class":236},"skGVy"," re\n",[204,239,241,244,247,249],{"class":107,"line":240},2,[204,242,243],{"class":232},"from",[204,245,246],{"class":236}," openpyxl ",[204,248,233],{"class":232},[204,250,251],{"class":236}," Workbook, load_workbook\n",[204,253,255,257,260,262],{"class":107,"line":254},3,[204,256,243],{"class":232},[204,258,259],{"class":236}," openpyxl.utils ",[204,261,233],{"class":232},[204,263,265],{"class":264},"sP0c6"," FORMULAE\n",[204,267,269,271,274,276],{"class":107,"line":268},4,[204,270,243],{"class":232},[204,272,273],{"class":236}," openpyxl.workbook.defined_name ",[204,275,233],{"class":232},[204,277,278],{"class":236}," DefinedName\n",[192,280,282],{"id":281},"step-1-add-the-_xlfn-prefix-to-newer-functions","Step 1 — Add the _xlfn. prefix to newer functions",[10,284,285],{},"When writing with openpyxl, put the prefix in the formula text yourself. Users never see it — Excel hides it in the formula bar — but the file needs it:",[14,287,289],{"className":223,"code":288,"language":225,"meta":20,"style":20},"wb = Workbook()\nws = wb.active\nws.append([\"sku\", \"price\"])\nws.append([\"A-1\", 4.5])\nws.append([\"B-2\", 7.25])\n\nws[\"D1\"] = '=_xlfn.XLOOKUP(\"B-2\",A2:A3,B2:B3)'\nws[\"D2\"] = '=_xlfn.TEXTJOIN(\", \",TRUE,A2:A3)'\nws[\"D3\"] = '=_xlfn.IFS(B2>5,\"high\",TRUE,\"low\")'\nws[\"D4\"] = '=_xlfn.STDEV.S(B2:B3)'\nwb.save(\"prefixed.xlsx\")\nprint([ws.cell(row=r, column=4).value for r in range(1, 5)])\n",[22,290,291,302,312,329,343,358,365,382,397,412,427,439],{"__ignoreMap":20},[204,292,293,296,299],{"class":107,"line":206},[204,294,295],{"class":236},"wb ",[204,297,298],{"class":232},"=",[204,300,301],{"class":236}," Workbook()\n",[204,303,304,307,309],{"class":107,"line":240},[204,305,306],{"class":236},"ws ",[204,308,298],{"class":232},[204,310,311],{"class":236}," wb.active\n",[204,313,314,317,320,323,326],{"class":107,"line":254},[204,315,316],{"class":236},"ws.append([",[204,318,319],{"class":213},"\"sku\"",[204,321,322],{"class":236},", ",[204,324,325],{"class":213},"\"price\"",[204,327,328],{"class":236},"])\n",[204,330,331,333,336,338,341],{"class":107,"line":268},[204,332,316],{"class":236},[204,334,335],{"class":213},"\"A-1\"",[204,337,322],{"class":236},[204,339,340],{"class":264},"4.5",[204,342,328],{"class":236},[204,344,346,348,351,353,356],{"class":107,"line":345},5,[204,347,316],{"class":236},[204,349,350],{"class":213},"\"B-2\"",[204,352,322],{"class":236},[204,354,355],{"class":264},"7.25",[204,357,328],{"class":236},[204,359,361],{"class":107,"line":360},6,[204,362,364],{"emptyLinePlaceholder":363},true,"\n",[204,366,368,371,374,377,379],{"class":107,"line":367},7,[204,369,370],{"class":236},"ws[",[204,372,373],{"class":213},"\"D1\"",[204,375,376],{"class":236},"] ",[204,378,298],{"class":232},[204,380,381],{"class":213}," '=_xlfn.XLOOKUP(\"B-2\",A2:A3,B2:B3)'\n",[204,383,385,387,390,392,394],{"class":107,"line":384},8,[204,386,370],{"class":236},[204,388,389],{"class":213},"\"D2\"",[204,391,376],{"class":236},[204,393,298],{"class":232},[204,395,396],{"class":213}," '=_xlfn.TEXTJOIN(\", \",TRUE,A2:A3)'\n",[204,398,400,402,405,407,409],{"class":107,"line":399},9,[204,401,370],{"class":236},[204,403,404],{"class":213},"\"D3\"",[204,406,376],{"class":236},[204,408,298],{"class":232},[204,410,411],{"class":213}," '=_xlfn.IFS(B2>5,\"high\",TRUE,\"low\")'\n",[204,413,415,417,420,422,424],{"class":107,"line":414},10,[204,416,370],{"class":236},[204,418,419],{"class":213},"\"D4\"",[204,421,376],{"class":236},[204,423,298],{"class":232},[204,425,426],{"class":213}," '=_xlfn.STDEV.S(B2:B3)'\n",[204,428,430,433,436],{"class":107,"line":429},11,[204,431,432],{"class":236},"wb.save(",[204,434,435],{"class":213},"\"prefixed.xlsx\"",[204,437,438],{"class":236},")\n",[204,440,442,445,448,452,454,457,460,462,464,467,470,473,476,479,482,485,487,490],{"class":107,"line":441},12,[204,443,444],{"class":264},"print",[204,446,447],{"class":236},"([ws.cell(",[204,449,451],{"class":450},"sa561","row",[204,453,298],{"class":232},[204,455,456],{"class":236},"r, ",[204,458,459],{"class":450},"column",[204,461,298],{"class":232},[204,463,74],{"class":264},[204,465,466],{"class":236},").value ",[204,468,469],{"class":232},"for",[204,471,472],{"class":236}," r ",[204,474,475],{"class":232},"in",[204,477,478],{"class":264}," range",[204,480,481],{"class":236},"(",[204,483,484],{"class":264},"1",[204,486,322],{"class":236},[204,488,489],{"class":264},"5",[204,491,492],{"class":236},")])\n",[10,494,495,496,322,498,322,501,322,504,322,507,322,510,322,513,322,516,322,519,322,522,322,525,322,528,322,531,322,534,322,537,322,540,322,543,322,546,549,550,322,553,556,557,560,561,556,564,567,568,556,571,574],{},"The functions that need it are the ones Excel gained from 2010 onwards: ",[22,497,41],{},[22,499,500],{},"XMATCH",[22,502,503],{},"TEXTJOIN",[22,505,506],{},"CONCAT",[22,508,509],{},"IFS",[22,511,512],{},"SWITCH",[22,514,515],{},"MAXIFS",[22,517,518],{},"MINIFS",[22,520,521],{},"IFNA",[22,523,524],{},"STDEV.S",[22,526,527],{},"STDEV.P",[22,529,530],{},"VAR.S",[22,532,533],{},"PERCENTILE.INC",[22,535,536],{},"RANK.EQ",[22,538,539],{},"AGGREGATE",[22,541,542],{},"DAYS",[22,544,545],{},"LET",[22,547,548],{},"LAMBDA",", the dynamic array functions such as ",[22,551,552],{},"UNIQUE",[22,554,555],{},"SEQUENCE"," and ",[22,558,559],{},"SORTBY",", and many statistics functions with dotted names. Two of the dynamic array functions have a longer prefix: ",[22,562,563],{},"FILTER",[22,565,566],{},"SORT"," are stored as ",[22,569,570],{},"_xlfn._xlws.FILTER",[22,572,573],{},"_xlfn._xlws.SORT",".",[10,576,577,578,582,583,586],{},"openpyxl ships the list of functions that do ",[579,580,581],"em",{},"not"," need a prefix, ",[22,584,585],{},"openpyxl.utils.FORMULAE",". Checking a name against it is the quickest test:",[14,588,590],{"className":223,"code":589,"language":225,"meta":20,"style":20},"for name in [\"SUM\", \"VLOOKUP\", \"SUMIFS\", \"IFERROR\", \"XLOOKUP\", \"TEXTJOIN\", \"IFS\", \"STDEV.S\"]:\n    print(f\"{name:9} {'plain' if name in FORMULAE else 'needs _xlfn. (or is misspelled)'}\")\n",[22,591,592,645],{"__ignoreMap":20},[204,593,594,596,599,601,604,607,609,612,614,617,619,622,624,627,629,632,634,637,639,642],{"class":107,"line":206},[204,595,469],{"class":232},[204,597,598],{"class":236}," name ",[204,600,475],{"class":232},[204,602,603],{"class":236}," [",[204,605,606],{"class":213},"\"SUM\"",[204,608,322],{"class":236},[204,610,611],{"class":213},"\"VLOOKUP\"",[204,613,322],{"class":236},[204,615,616],{"class":213},"\"SUMIFS\"",[204,618,322],{"class":236},[204,620,621],{"class":213},"\"IFERROR\"",[204,623,322],{"class":236},[204,625,626],{"class":213},"\"XLOOKUP\"",[204,628,322],{"class":236},[204,630,631],{"class":213},"\"TEXTJOIN\"",[204,633,322],{"class":236},[204,635,636],{"class":213},"\"IFS\"",[204,638,322],{"class":236},[204,640,641],{"class":213},"\"STDEV.S\"",[204,643,644],{"class":236},"]:\n",[204,646,647,650,652,655,658,662,665,668,671,674,677,680,682,684,687,690,693,695,697],{"class":107,"line":240},[204,648,649],{"class":264},"    print",[204,651,481],{"class":236},[204,653,654],{"class":232},"f",[204,656,657],{"class":213},"\"",[204,659,661],{"class":660},"sSjpA","{",[204,663,664],{"class":236},"name",[204,666,667],{"class":232},":9",[204,669,670],{"class":660},"}",[204,672,673],{"class":660}," {",[204,675,676],{"class":213},"'plain'",[204,678,679],{"class":232}," if",[204,681,598],{"class":236},[204,683,475],{"class":232},[204,685,686],{"class":264}," FORMULAE",[204,688,689],{"class":232}," else",[204,691,692],{"class":213}," 'needs _xlfn. (or is misspelled)'",[204,694,670],{"class":660},[204,696,657],{"class":213},[204,698,438],{"class":236},[192,700,702],{"id":701},"step-2-or-let-xlsxwriter-add-prefixes-for-you","Step 2 — Or let xlsxwriter add prefixes for you",[10,704,705,706,709],{},"When the workbook is new, xlsxwriter can apply the prefixes itself. Pass ",[22,707,708],{},"use_future_functions"," when creating the workbook and write formulas the way you would type them:",[14,711,713],{"className":223,"code":712,"language":225,"meta":20,"style":20},"import xlsxwriter\nimport zipfile\n\nbook = xlsxwriter.Workbook(\"auto_prefixed.xlsx\", {\"use_future_functions\": True})\nsheet = book.add_worksheet()\nsheet.write_column(\"A1\", [\"A-1\", \"B-2\"])\nsheet.write_column(\"B1\", [4.5, 7.25])\nsheet.write_formula(\"D1\", '=XLOOKUP(\"B-2\",A1:A2,B1:B2)')\nsheet.write_formula(\"D2\", \"=STDEV.S(B1:B2)\")\nsheet.write_formula(\"D3\", \"=FILTER(A1:A2,B1:B2>5)\")\nbook.close()\n\nwith zipfile.ZipFile(\"auto_prefixed.xlsx\") as z:\n    xml = z.read(\"xl\u002Fworksheets\u002Fsheet1.xml\").decode()\nprint(re.findall(r\"\u003Cf[^>]*>(.*?)\u003C\u002Ff>\", xml))\n",[22,714,715,721,728,732,760,770,789,806,820,833,846,851,855,875,892],{"__ignoreMap":20},[204,716,717,719],{"class":107,"line":206},[204,718,233],{"class":232},[204,720,220],{"class":236},[204,722,723,725],{"class":107,"line":240},[204,724,233],{"class":232},[204,726,727],{"class":236}," zipfile\n",[204,729,730],{"class":107,"line":254},[204,731,364],{"emptyLinePlaceholder":363},[204,733,734,737,739,742,745,748,751,754,757],{"class":107,"line":268},[204,735,736],{"class":236},"book ",[204,738,298],{"class":232},[204,740,741],{"class":236}," xlsxwriter.Workbook(",[204,743,744],{"class":213},"\"auto_prefixed.xlsx\"",[204,746,747],{"class":236},", {",[204,749,750],{"class":213},"\"use_future_functions\"",[204,752,753],{"class":236},": ",[204,755,756],{"class":264},"True",[204,758,759],{"class":236},"})\n",[204,761,762,765,767],{"class":107,"line":345},[204,763,764],{"class":236},"sheet ",[204,766,298],{"class":232},[204,768,769],{"class":236}," book.add_worksheet()\n",[204,771,772,775,778,781,783,785,787],{"class":107,"line":360},[204,773,774],{"class":236},"sheet.write_column(",[204,776,777],{"class":213},"\"A1\"",[204,779,780],{"class":236},", [",[204,782,335],{"class":213},[204,784,322],{"class":236},[204,786,350],{"class":213},[204,788,328],{"class":236},[204,790,791,793,796,798,800,802,804],{"class":107,"line":367},[204,792,774],{"class":236},[204,794,795],{"class":213},"\"B1\"",[204,797,780],{"class":236},[204,799,340],{"class":264},[204,801,322],{"class":236},[204,803,355],{"class":264},[204,805,328],{"class":236},[204,807,808,811,813,815,818],{"class":107,"line":384},[204,809,810],{"class":236},"sheet.write_formula(",[204,812,373],{"class":213},[204,814,322],{"class":236},[204,816,817],{"class":213},"'=XLOOKUP(\"B-2\",A1:A2,B1:B2)'",[204,819,438],{"class":236},[204,821,822,824,826,828,831],{"class":107,"line":399},[204,823,810],{"class":236},[204,825,389],{"class":213},[204,827,322],{"class":236},[204,829,830],{"class":213},"\"=STDEV.S(B1:B2)\"",[204,832,438],{"class":236},[204,834,835,837,839,841,844],{"class":107,"line":414},[204,836,810],{"class":236},[204,838,404],{"class":213},[204,840,322],{"class":236},[204,842,843],{"class":213},"\"=FILTER(A1:A2,B1:B2>5)\"",[204,845,438],{"class":236},[204,847,848],{"class":107,"line":429},[204,849,850],{"class":236},"book.close()\n",[204,852,853],{"class":107,"line":441},[204,854,364],{"emptyLinePlaceholder":363},[204,856,858,861,864,866,869,872],{"class":107,"line":857},13,[204,859,860],{"class":232},"with",[204,862,863],{"class":236}," zipfile.ZipFile(",[204,865,744],{"class":213},[204,867,868],{"class":236},") ",[204,870,871],{"class":232},"as",[204,873,874],{"class":236}," z:\n",[204,876,878,881,883,886,889],{"class":107,"line":877},14,[204,879,880],{"class":236},"    xml ",[204,882,298],{"class":232},[204,884,885],{"class":236}," z.read(",[204,887,888],{"class":213},"\"xl\u002Fworksheets\u002Fsheet1.xml\"",[204,890,891],{"class":236},").decode()\n",[204,893,895,897,900,903,906,909,912,915,918,921,923,926,929,932,935],{"class":107,"line":894},15,[204,896,444],{"class":264},[204,898,899],{"class":236},"(re.findall(",[204,901,902],{"class":232},"r",[204,904,905],{"class":213},"\"\u003Cf",[204,907,908],{"class":264},"[",[204,910,911],{"class":232},"^",[204,913,914],{"class":660},">",[204,916,917],{"class":264},"]",[204,919,920],{"class":232},"*",[204,922,914],{"class":213},[204,924,925],{"class":264},"(.",[204,927,928],{"class":232},"*?",[204,930,931],{"class":264},")",[204,933,934],{"class":213},"\u003C\u002Ff>\"",[204,936,937],{"class":236},", xml))\n",[10,939,940,941,943,944,322,946,949,950,953,954,957,958,962],{},"The stored formulas carry ",[22,942,37],{}," and, for ",[22,945,563],{},[22,947,948],{},"_xlfn._xlws.",". With pandas, pass the same option through ",[22,951,952],{},"engine_kwargs={\"options\": {\"use_future_functions\": True}}"," on an ",[22,955,956],{},"ExcelWriter"," using the xlsxwriter engine. Dynamic array functions have one more storage detail — they are written as array formulas so the results can spill — which ",[47,959,961],{"href":960},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-dynamic-array-formulas-with-python\u002F","Write Dynamic Array Formulas like FILTER and UNIQUE from Python"," covers.",[192,964,966],{"id":965},"step-3-check-the-other-causes-of-name","Step 3 — Check the other causes of #NAME?",[10,968,969],{},"If the function is an old one, or already prefixed, the error has one of these causes instead. Each was confirmed by writing it with openpyxl and recalculating:",[53,971,62,976,62,979,62,982,62,985,62,990,62,997,62,1003,62,1005,62,1009,62,1012,62,1016,62,1021,62,1026,62,1028,62,1033,62,1035,62,1037,62,1039,62,1042,62,1045,62,1049,62,1051,62,1054,62,1056,62,1058,62,1060,62,1063,62,1066,62,1070,62,1072,62,1076,62,1078,62,1080,62,1082,62,1085,62,1088,62,1092,62,1094,62,1098,62,1100,62,1102,62,1104,62,1107,62,1110,62,1114,62,1116,62,1120,62,1122,62,1124,62,1126],{"viewBox":972,"role":56,"ariaLabelledBy":973,"xmlns":60,"style":61},"4 0 752 242",[974,975],"nme-causes-t","nme-causes-d",[64,977,978],{"id":974},"Causes of #NAME? in generated formulas",[68,980,981],{"id":975},"A table of formulas and results after recalculation. =XLOOKUP without a prefix gives #NAME?. =SUM(Sales) where no name Sales is defined gives #NAME?. =IF(A2=a,...) with unquoted text gives #NAME?. =SUMA(B2:B3), a localised function name, gives #NAME?. The corrected versions — prefixed function, defined name, quoted text and English function name — all calculate.",[72,983],{"x":74,"y":75,"width":76,"height":984,"fill":78},"242",[72,986],{"x":81,"y":82,"width":987,"height":988,"rx":75,"fill":78,"stroke":989,"style":112},"136.5","40.0","var(--line,#cdd5e6)",[72,991],{"x":992,"y":82,"width":993,"height":988,"rx":75,"fill":994,"stroke":995,"style":996},"156.5","194.5","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.2px",[19,998,1002],{"x":999,"y":1000,"style":1001},"253.8","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Written",[72,1004],{"x":83,"y":82,"width":993,"height":988,"rx":75,"fill":994,"stroke":995,"style":996},[19,1006,1008],{"x":1007,"y":1000,"style":1001},"448.3","Result",[72,1010],{"x":1011,"y":82,"width":993,"height":988,"rx":75,"fill":994,"stroke":995,"style":996},"545.5",[19,1013,1015],{"x":1014,"y":1000,"style":1001},"642.8","Fix",[72,1017],{"x":81,"y":1018,"width":987,"height":1019,"rx":75,"fill":1020,"stroke":989,"style":112},"56.0","34.0","#e7ebef",[19,1022,1025],{"x":1023,"y":103,"style":1024},"32.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","Missing prefix",[72,1027],{"x":992,"y":1018,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1029,1032],{"x":999,"y":1030,"style":1031},"77.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","=XLOOKUP(…)",[72,1034],{"x":83,"y":1018,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1036,29],{"x":1007,"y":1030,"style":1031},[72,1038],{"x":1011,"y":1018,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1040,1041],{"x":1014,"y":1030,"style":1031},"=_xlfn.XLOOKUP(…)",[72,1043],{"x":81,"y":1044,"width":987,"height":1019,"rx":75,"fill":1020,"stroke":989,"style":112},"90.0",[19,1046,1048],{"x":1023,"y":1047,"style":1024},"112.0","Undefined name",[72,1050],{"x":992,"y":1044,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1052,1053],{"x":999,"y":116,"style":1031},"=SUM(Sales)",[72,1055],{"x":83,"y":1044,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1057,29],{"x":1007,"y":116,"style":1031},[72,1059],{"x":1011,"y":1044,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1061,1062],{"x":1014,"y":116,"style":1031},"define the name first",[72,1064],{"x":81,"y":1065,"width":987,"height":1019,"rx":75,"fill":1020,"stroke":989,"style":112},"124.0",[19,1067,1069],{"x":1023,"y":1068,"style":1024},"146.0","Unquoted text",[72,1071],{"x":992,"y":1065,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1073,1075],{"x":999,"y":1074,"style":1031},"145.0","=IF(A2=a,…)",[72,1077],{"x":83,"y":1065,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1079,29],{"x":1007,"y":1074,"style":1031},[72,1081],{"x":1011,"y":1065,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1083,1084],{"x":1014,"y":1074,"style":1031},"=IF(A2=\"a\",…)",[72,1086],{"x":81,"y":1087,"width":987,"height":1019,"rx":75,"fill":1020,"stroke":989,"style":112},"158.0",[19,1089,1091],{"x":1023,"y":1090,"style":1024},"180.0","Localised name",[72,1093],{"x":992,"y":1087,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1095,1097],{"x":999,"y":1096,"style":1031},"179.0","=SUMA(B2:B3)",[72,1099],{"x":83,"y":1087,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1101,29],{"x":1007,"y":1096,"style":1031},[72,1103],{"x":1011,"y":1087,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1105,1106],{"x":1014,"y":1096,"style":1031},"=SUM(B2:B3)",[72,1108],{"x":81,"y":1109,"width":987,"height":1019,"rx":75,"fill":1020,"stroke":989,"style":112},"192.0",[19,1111,1113],{"x":1023,"y":1112,"style":1024},"214.0","Misspelled name",[72,1115],{"x":992,"y":1109,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1117,1119],{"x":999,"y":1118,"style":1031},"213.0","=SUMM(B2:B3)",[72,1121],{"x":83,"y":1109,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1123,29],{"x":1007,"y":1118,"style":1031},[72,1125],{"x":1011,"y":1109,"width":993,"height":1019,"rx":75,"fill":78,"stroke":989,"style":112},[19,1127,1106],{"x":1014,"y":1118,"style":1031},[10,1129,1130,1134],{},[1131,1132,1133],"strong",{},"Undefined names."," A formula that refers to a named range the workbook does not have — because the name was never created, or was created with a typo, or belongs to a different workbook — fails the same way. Create the defined name before relying on it:",[14,1136,1138],{"className":223,"code":1137,"language":225,"meta":20,"style":20},"wb = Workbook()\nws = wb.active\nws.title = \"Data\"\nws.append([\"amount\"])\nws.append([120])\nws.append([80])\nwb.defined_names[\"Amounts\"] = DefinedName(\"Amounts\", attr_text=\"Data!$A$2:$A$3\")\nws[\"C1\"] = \"=SUM(Amounts)\"\nwb.save(\"named.xlsx\")\nprint(list(wb.defined_names.keys()))\n",[22,1139,1140,1148,1156,1166,1175,1184,1193,1222,1236,1245],{"__ignoreMap":20},[204,1141,1142,1144,1146],{"class":107,"line":206},[204,1143,295],{"class":236},[204,1145,298],{"class":232},[204,1147,301],{"class":236},[204,1149,1150,1152,1154],{"class":107,"line":240},[204,1151,306],{"class":236},[204,1153,298],{"class":232},[204,1155,311],{"class":236},[204,1157,1158,1161,1163],{"class":107,"line":254},[204,1159,1160],{"class":236},"ws.title ",[204,1162,298],{"class":232},[204,1164,1165],{"class":213}," \"Data\"\n",[204,1167,1168,1170,1173],{"class":107,"line":268},[204,1169,316],{"class":236},[204,1171,1172],{"class":213},"\"amount\"",[204,1174,328],{"class":236},[204,1176,1177,1179,1182],{"class":107,"line":345},[204,1178,316],{"class":236},[204,1180,1181],{"class":264},"120",[204,1183,328],{"class":236},[204,1185,1186,1188,1191],{"class":107,"line":360},[204,1187,316],{"class":236},[204,1189,1190],{"class":264},"80",[204,1192,328],{"class":236},[204,1194,1195,1198,1201,1203,1205,1208,1210,1212,1215,1217,1220],{"class":107,"line":367},[204,1196,1197],{"class":236},"wb.defined_names[",[204,1199,1200],{"class":213},"\"Amounts\"",[204,1202,376],{"class":236},[204,1204,298],{"class":232},[204,1206,1207],{"class":236}," DefinedName(",[204,1209,1200],{"class":213},[204,1211,322],{"class":236},[204,1213,1214],{"class":450},"attr_text",[204,1216,298],{"class":232},[204,1218,1219],{"class":213},"\"Data!$A$2:$A$3\"",[204,1221,438],{"class":236},[204,1223,1224,1226,1229,1231,1233],{"class":107,"line":384},[204,1225,370],{"class":236},[204,1227,1228],{"class":213},"\"C1\"",[204,1230,376],{"class":236},[204,1232,298],{"class":232},[204,1234,1235],{"class":213}," \"=SUM(Amounts)\"\n",[204,1237,1238,1240,1243],{"class":107,"line":399},[204,1239,432],{"class":236},[204,1241,1242],{"class":213},"\"named.xlsx\"",[204,1244,438],{"class":236},[204,1246,1247,1249,1251,1254],{"class":107,"line":414},[204,1248,444],{"class":264},[204,1250,481],{"class":236},[204,1252,1253],{"class":264},"list",[204,1255,1256],{"class":236},"(wb.defined_names.keys()))\n",[10,1258,1259,1262,1263,1266,1267,1270],{},[1131,1260,1261],{},"Text without quotes."," Inside a formula, a bare word is read as a name. ",[22,1264,1265],{},"=IF(A2=Yes,...)"," looks for a defined name called ",[22,1268,1269],{},"Yes",". Text constants need double quotes, which is easy to get wrong when a formula is assembled with an f-string. Build formula text with a helper that quotes values, and double any quotes inside them:",[14,1272,1274],{"className":223,"code":1273,"language":225,"meta":20,"style":20},"def xl_text(value):\n    return '\"' + str(value).replace('\"', '\"\"') + '\"'\n\nstatus = 'Say \"yes\"'\nprint(f\"=IF(A2={xl_text(status)},1,0)\")\n# =IF(A2=\"Say \"\"yes\"\"\",1,0)\n",[22,1275,1276,1288,1321,1325,1335,1358],{"__ignoreMap":20},[204,1277,1278,1281,1285],{"class":107,"line":206},[204,1279,1280],{"class":232},"def",[204,1282,1284],{"class":1283},"s_Opv"," xl_text",[204,1286,1287],{"class":236},"(value):\n",[204,1289,1290,1293,1296,1299,1302,1305,1308,1310,1313,1315,1318],{"class":107,"line":240},[204,1291,1292],{"class":232},"    return",[204,1294,1295],{"class":213}," '\"'",[204,1297,1298],{"class":232}," +",[204,1300,1301],{"class":264}," str",[204,1303,1304],{"class":236},"(value).replace(",[204,1306,1307],{"class":213},"'\"'",[204,1309,322],{"class":236},[204,1311,1312],{"class":213},"'\"\"'",[204,1314,868],{"class":236},[204,1316,1317],{"class":232},"+",[204,1319,1320],{"class":213}," '\"'\n",[204,1322,1323],{"class":107,"line":254},[204,1324,364],{"emptyLinePlaceholder":363},[204,1326,1327,1330,1332],{"class":107,"line":268},[204,1328,1329],{"class":236},"status ",[204,1331,298],{"class":232},[204,1333,1334],{"class":213}," 'Say \"yes\"'\n",[204,1336,1337,1339,1341,1343,1346,1348,1351,1353,1356],{"class":107,"line":345},[204,1338,444],{"class":264},[204,1340,481],{"class":236},[204,1342,654],{"class":232},[204,1344,1345],{"class":213},"\"=IF(A2=",[204,1347,661],{"class":660},[204,1349,1350],{"class":236},"xl_text(status)",[204,1352,670],{"class":660},[204,1354,1355],{"class":213},",1,0)\"",[204,1357,438],{"class":236},[204,1359,1360],{"class":107,"line":360},[204,1361,1363],{"class":1362},"s-wDw","# =IF(A2=\"Say \"\"yes\"\"\",1,0)\n",[10,1365,1366,1369,1370,322,1373,1376,1377,574],{},[1131,1367,1368],{},"Localised function names and separators."," The file format always uses English function names and commas between arguments. A formula copied from a German or Spanish Excel — ",[22,1371,1372],{},"=SUMME(A1;A2)",[22,1374,1375],{},"=SUMA(A1;A2)"," — must be translated before it is written; Excel converts it back to the reader's language on screen. Semicolons as separators produce errors as well, though not always ",[22,1378,29],{},[10,1380,1381,1384,1385,1388,1389,1391,1392,1395,1396,1400],{},[1131,1382,1383],{},"Sheet names with spaces."," ",[22,1386,1387],{},"=Sales Data!A1"," is not ",[22,1390,29],{}," but it is still broken: sheet names containing spaces or punctuation must be quoted, ",[22,1393,1394],{},"='Sales Data'!A1",". ",[47,1397,1399],{"href":1398},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formulas-that-reference-other-sheets-with-openpyxl\u002F","Write Formulas That Reference Other Sheets with openpyxl"," has a helper that quotes them correctly.",[192,1402,1404],{"id":1403},"step-4-lint-every-formula-before-saving","Step 4 — Lint every formula before saving",[10,1406,1407,1408,1411],{},"Collect the rules into one function that inspects every formula in a workbook and reports what would break. It lists function names that are neither in ",[22,1409,1410],{},"FORMULAE"," nor prefixed, names that look like defined names but are not defined, and can apply the prefix for functions you tell it about:",[14,1413,1415],{"className":223,"code":1414,"language":225,"meta":20,"style":20},"FUNC = re.compile(r\"(?\u003C![\\w.])([A-Z][A-Z0-9]*(?:\\.[A-Z0-9]+)*)\\(\")\nPREFIX = {\"XLOOKUP\": \"_xlfn.\", \"XMATCH\": \"_xlfn.\", \"TEXTJOIN\": \"_xlfn.\", \"CONCAT\": \"_xlfn.\",\n          \"IFS\": \"_xlfn.\", \"SWITCH\": \"_xlfn.\", \"MAXIFS\": \"_xlfn.\", \"MINIFS\": \"_xlfn.\",\n          \"IFNA\": \"_xlfn.\", \"STDEV.S\": \"_xlfn.\", \"STDEV.P\": \"_xlfn.\", \"LET\": \"_xlfn.\",\n          \"UNIQUE\": \"_xlfn.\", \"FILTER\": \"_xlfn._xlws.\", \"SORT\": \"_xlfn._xlws.\"}\n\ndef lint_formulas(wb, fix=False):\n    problems = []\n    for ws in wb.worksheets:\n        for row in ws.iter_rows():\n            for cell in row:\n                if not (isinstance(cell.value, str) and cell.value.startswith(\"=\")):\n                    continue\n                text = re.sub(r'\"[^\"]*\"', '\"\"', cell.value)      # ignore string literals\n                for name in set(FUNC.findall(text)):\n                    if name in FORMULAE:\n                        continue\n                    if fix and name in PREFIX:\n                        cell.value = re.sub(rf\"(?\u003C![\\w.]){re.escape(name)}\\(\",\n                                            PREFIX[name] + name + \"(\", cell.value)\n                    else:\n                        problems.append(f\"{ws.title}!{cell.coordinate}: unknown function {name}\")\n    return problems\n\nwb = Workbook()\nws = wb.active\nws[\"A1\"] = '=XLOOKUP(\"x\",B1:B2,C1:C2)'\nws[\"A2\"] = \"=SUMM(B1:B2)\"\nws[\"A3\"] = '=IF(B1=\"IFS(\",1,0)'\nprint(lint_formulas(wb))\nprint(lint_formulas(wb, fix=True), ws[\"A1\"].value)\n",[22,1416,1417,1488,1533,1571,1608,1639,1643,1661,1671,1684,1697,1710,1744,1749,1787,1806,1821,1827,1846,1874,1895,1903,1943,1951,1956,1965,1974,1988,2003,2018,2026],{"__ignoreMap":20},[204,1418,1419,1422,1425,1428,1430,1432,1435,1438,1440,1442,1444,1447,1450,1453,1456,1458,1460,1463,1467,1469,1471,1473,1475,1477,1479,1481,1484,1486],{"class":107,"line":206},[204,1420,1421],{"class":264},"FUNC",[204,1423,1424],{"class":232}," =",[204,1426,1427],{"class":236}," re.compile(",[204,1429,902],{"class":232},[204,1431,657],{"class":213},[204,1433,1434],{"class":232},"(?\u003C!",[204,1436,1437],{"class":264},"[\\w",[204,1439,574],{"class":660},[204,1441,917],{"class":264},[204,1443,931],{"class":232},[204,1445,1446],{"class":264},"([",[204,1448,1449],{"class":660},"A-Z",[204,1451,1452],{"class":264},"][",[204,1454,1455],{"class":660},"A-Z0-9",[204,1457,917],{"class":264},[204,1459,920],{"class":232},[204,1461,1462],{"class":264},"(?:",[204,1464,1466],{"class":1465},"s_b0D","\\.",[204,1468,908],{"class":264},[204,1470,1455],{"class":660},[204,1472,917],{"class":264},[204,1474,1317],{"class":232},[204,1476,931],{"class":264},[204,1478,920],{"class":232},[204,1480,931],{"class":264},[204,1482,1483],{"class":1465},"\\(",[204,1485,657],{"class":213},[204,1487,438],{"class":236},[204,1489,1490,1493,1495,1497,1499,1501,1504,1506,1509,1511,1513,1515,1517,1519,1521,1523,1526,1528,1530],{"class":107,"line":240},[204,1491,1492],{"class":264},"PREFIX",[204,1494,1424],{"class":232},[204,1496,673],{"class":236},[204,1498,626],{"class":213},[204,1500,753],{"class":236},[204,1502,1503],{"class":213},"\"_xlfn.\"",[204,1505,322],{"class":236},[204,1507,1508],{"class":213},"\"XMATCH\"",[204,1510,753],{"class":236},[204,1512,1503],{"class":213},[204,1514,322],{"class":236},[204,1516,631],{"class":213},[204,1518,753],{"class":236},[204,1520,1503],{"class":213},[204,1522,322],{"class":236},[204,1524,1525],{"class":213},"\"CONCAT\"",[204,1527,753],{"class":236},[204,1529,1503],{"class":213},[204,1531,1532],{"class":236},",\n",[204,1534,1535,1538,1540,1542,1544,1547,1549,1551,1553,1556,1558,1560,1562,1565,1567,1569],{"class":107,"line":254},[204,1536,1537],{"class":213},"          \"IFS\"",[204,1539,753],{"class":236},[204,1541,1503],{"class":213},[204,1543,322],{"class":236},[204,1545,1546],{"class":213},"\"SWITCH\"",[204,1548,753],{"class":236},[204,1550,1503],{"class":213},[204,1552,322],{"class":236},[204,1554,1555],{"class":213},"\"MAXIFS\"",[204,1557,753],{"class":236},[204,1559,1503],{"class":213},[204,1561,322],{"class":236},[204,1563,1564],{"class":213},"\"MINIFS\"",[204,1566,753],{"class":236},[204,1568,1503],{"class":213},[204,1570,1532],{"class":236},[204,1572,1573,1576,1578,1580,1582,1584,1586,1588,1590,1593,1595,1597,1599,1602,1604,1606],{"class":107,"line":268},[204,1574,1575],{"class":213},"          \"IFNA\"",[204,1577,753],{"class":236},[204,1579,1503],{"class":213},[204,1581,322],{"class":236},[204,1583,641],{"class":213},[204,1585,753],{"class":236},[204,1587,1503],{"class":213},[204,1589,322],{"class":236},[204,1591,1592],{"class":213},"\"STDEV.P\"",[204,1594,753],{"class":236},[204,1596,1503],{"class":213},[204,1598,322],{"class":236},[204,1600,1601],{"class":213},"\"LET\"",[204,1603,753],{"class":236},[204,1605,1503],{"class":213},[204,1607,1532],{"class":236},[204,1609,1610,1613,1615,1617,1619,1622,1624,1627,1629,1632,1634,1636],{"class":107,"line":345},[204,1611,1612],{"class":213},"          \"UNIQUE\"",[204,1614,753],{"class":236},[204,1616,1503],{"class":213},[204,1618,322],{"class":236},[204,1620,1621],{"class":213},"\"FILTER\"",[204,1623,753],{"class":236},[204,1625,1626],{"class":213},"\"_xlfn._xlws.\"",[204,1628,322],{"class":236},[204,1630,1631],{"class":213},"\"SORT\"",[204,1633,753],{"class":236},[204,1635,1626],{"class":213},[204,1637,1638],{"class":236},"}\n",[204,1640,1641],{"class":107,"line":360},[204,1642,364],{"emptyLinePlaceholder":363},[204,1644,1645,1647,1650,1653,1655,1658],{"class":107,"line":367},[204,1646,1280],{"class":232},[204,1648,1649],{"class":1283}," lint_formulas",[204,1651,1652],{"class":236},"(wb, fix",[204,1654,298],{"class":232},[204,1656,1657],{"class":264},"False",[204,1659,1660],{"class":236},"):\n",[204,1662,1663,1666,1668],{"class":107,"line":384},[204,1664,1665],{"class":236},"    problems ",[204,1667,298],{"class":232},[204,1669,1670],{"class":236}," []\n",[204,1672,1673,1676,1679,1681],{"class":107,"line":399},[204,1674,1675],{"class":232},"    for",[204,1677,1678],{"class":236}," ws ",[204,1680,475],{"class":232},[204,1682,1683],{"class":236}," wb.worksheets:\n",[204,1685,1686,1689,1692,1694],{"class":107,"line":414},[204,1687,1688],{"class":232},"        for",[204,1690,1691],{"class":236}," row ",[204,1693,475],{"class":232},[204,1695,1696],{"class":236}," ws.iter_rows():\n",[204,1698,1699,1702,1705,1707],{"class":107,"line":429},[204,1700,1701],{"class":232},"            for",[204,1703,1704],{"class":236}," cell ",[204,1706,475],{"class":232},[204,1708,1709],{"class":236}," row:\n",[204,1711,1712,1715,1718,1721,1724,1727,1730,1732,1735,1738,1741],{"class":107,"line":441},[204,1713,1714],{"class":232},"                if",[204,1716,1717],{"class":232}," not",[204,1719,1720],{"class":236}," (",[204,1722,1723],{"class":264},"isinstance",[204,1725,1726],{"class":236},"(cell.value, ",[204,1728,1729],{"class":264},"str",[204,1731,868],{"class":236},[204,1733,1734],{"class":232},"and",[204,1736,1737],{"class":236}," cell.value.startswith(",[204,1739,1740],{"class":213},"\"=\"",[204,1742,1743],{"class":236},")):\n",[204,1745,1746],{"class":107,"line":857},[204,1747,1748],{"class":232},"                    continue\n",[204,1750,1751,1754,1756,1759,1761,1764,1766,1768,1770,1772,1774,1777,1779,1781,1784],{"class":107,"line":877},[204,1752,1753],{"class":236},"                text ",[204,1755,298],{"class":232},[204,1757,1758],{"class":236}," re.sub(",[204,1760,902],{"class":232},[204,1762,1763],{"class":213},"'\"",[204,1765,908],{"class":264},[204,1767,911],{"class":232},[204,1769,657],{"class":660},[204,1771,917],{"class":264},[204,1773,920],{"class":232},[204,1775,1776],{"class":213},"\"'",[204,1778,322],{"class":236},[204,1780,1312],{"class":213},[204,1782,1783],{"class":236},", cell.value)      ",[204,1785,1786],{"class":1362},"# ignore string literals\n",[204,1788,1789,1792,1794,1796,1799,1801,1803],{"class":107,"line":894},[204,1790,1791],{"class":232},"                for",[204,1793,598],{"class":236},[204,1795,475],{"class":232},[204,1797,1798],{"class":264}," set",[204,1800,481],{"class":236},[204,1802,1421],{"class":264},[204,1804,1805],{"class":236},".findall(text)):\n",[204,1807,1809,1812,1814,1816,1818],{"class":107,"line":1808},16,[204,1810,1811],{"class":232},"                    if",[204,1813,598],{"class":236},[204,1815,475],{"class":232},[204,1817,686],{"class":264},[204,1819,1820],{"class":236},":\n",[204,1822,1824],{"class":107,"line":1823},17,[204,1825,1826],{"class":232},"                        continue\n",[204,1828,1830,1832,1835,1837,1839,1841,1844],{"class":107,"line":1829},18,[204,1831,1811],{"class":232},[204,1833,1834],{"class":236}," fix ",[204,1836,1734],{"class":232},[204,1838,598],{"class":236},[204,1840,475],{"class":232},[204,1842,1843],{"class":264}," PREFIX",[204,1845,1820],{"class":236},[204,1847,1849,1852,1854,1856,1859,1862,1864,1867,1869,1872],{"class":107,"line":1848},19,[204,1850,1851],{"class":236},"                        cell.value ",[204,1853,298],{"class":232},[204,1855,1758],{"class":236},[204,1857,1858],{"class":232},"rf",[204,1860,1861],{"class":213},"\"(?\u003C![\\w.])",[204,1863,661],{"class":660},[204,1865,1866],{"class":236},"re.escape(name)",[204,1868,670],{"class":660},[204,1870,1871],{"class":213},"\\(\"",[204,1873,1532],{"class":236},[204,1875,1877,1880,1883,1885,1887,1889,1892],{"class":107,"line":1876},20,[204,1878,1879],{"class":264},"                                            PREFIX",[204,1881,1882],{"class":236},"[name] ",[204,1884,1317],{"class":232},[204,1886,598],{"class":236},[204,1888,1317],{"class":232},[204,1890,1891],{"class":213}," \"(\"",[204,1893,1894],{"class":236},", cell.value)\n",[204,1896,1898,1901],{"class":107,"line":1897},21,[204,1899,1900],{"class":232},"                    else",[204,1902,1820],{"class":236},[204,1904,1906,1909,1911,1913,1915,1918,1920,1923,1925,1928,1930,1933,1935,1937,1939,1941],{"class":107,"line":1905},22,[204,1907,1908],{"class":236},"                        problems.append(",[204,1910,654],{"class":232},[204,1912,657],{"class":213},[204,1914,661],{"class":660},[204,1916,1917],{"class":236},"ws.title",[204,1919,670],{"class":660},[204,1921,1922],{"class":213},"!",[204,1924,661],{"class":660},[204,1926,1927],{"class":236},"cell.coordinate",[204,1929,670],{"class":660},[204,1931,1932],{"class":213},": unknown function ",[204,1934,661],{"class":660},[204,1936,664],{"class":236},[204,1938,670],{"class":660},[204,1940,657],{"class":213},[204,1942,438],{"class":236},[204,1944,1946,1948],{"class":107,"line":1945},23,[204,1947,1292],{"class":232},[204,1949,1950],{"class":236}," problems\n",[204,1952,1954],{"class":107,"line":1953},24,[204,1955,364],{"emptyLinePlaceholder":363},[204,1957,1959,1961,1963],{"class":107,"line":1958},25,[204,1960,295],{"class":236},[204,1962,298],{"class":232},[204,1964,301],{"class":236},[204,1966,1968,1970,1972],{"class":107,"line":1967},26,[204,1969,306],{"class":236},[204,1971,298],{"class":232},[204,1973,311],{"class":236},[204,1975,1977,1979,1981,1983,1985],{"class":107,"line":1976},27,[204,1978,370],{"class":236},[204,1980,777],{"class":213},[204,1982,376],{"class":236},[204,1984,298],{"class":232},[204,1986,1987],{"class":213}," '=XLOOKUP(\"x\",B1:B2,C1:C2)'\n",[204,1989,1991,1993,1996,1998,2000],{"class":107,"line":1990},28,[204,1992,370],{"class":236},[204,1994,1995],{"class":213},"\"A2\"",[204,1997,376],{"class":236},[204,1999,298],{"class":232},[204,2001,2002],{"class":213}," \"=SUMM(B1:B2)\"\n",[204,2004,2006,2008,2011,2013,2015],{"class":107,"line":2005},29,[204,2007,370],{"class":236},[204,2009,2010],{"class":213},"\"A3\"",[204,2012,376],{"class":236},[204,2014,298],{"class":232},[204,2016,2017],{"class":213}," '=IF(B1=\"IFS(\",1,0)'\n",[204,2019,2021,2023],{"class":107,"line":2020},30,[204,2022,444],{"class":264},[204,2024,2025],{"class":236},"(lint_formulas(wb))\n",[204,2027,2029,2031,2034,2037,2039,2041,2044,2046],{"class":107,"line":2028},31,[204,2030,444],{"class":264},[204,2032,2033],{"class":236},"(lint_formulas(wb, ",[204,2035,2036],{"class":450},"fix",[204,2038,298],{"class":232},[204,2040,756],{"class":264},[204,2042,2043],{"class":236},"), ws[",[204,2045,777],{"class":213},[204,2047,2048],{"class":236},"].value)\n",[10,2050,2051,2052,2054,2055,2058,2059,2062,2063,2066],{},"The first run reports both the missing prefix and the typo. The second run prefixes ",[22,2053,41],{}," and leaves only ",[22,2056,2057],{},"SUMM",", which no automatic fix should guess at. Text inside quotes — the ",[22,2060,2061],{},"\"IFS(\""," in A3 — is ignored, so string literals never trigger false alarms. Call the linter in the job's tests or just before ",[22,2064,2065],{},"wb.save()",", and fail the run if it returns anything.",[53,2068,62,2073,62,2076,62,2079,62,2082,62,2087,62,2095,62,2101,62,2105,62,2110,62,2115,62,2118,62,2124,62,2129,62,2133,62,2137,62,2140,62,2143,62,2146,62,2152,62,2157,62,2161,62,2164,62,2168,62,2171,62,2175,62,2181,62,2187,62,2191,62,2194],{"viewBox":2069,"role":56,"ariaLabelledBy":2070,"xmlns":60,"style":61},"4 0 752 160",[2071,2072],"nme-lint-t","nme-lint-d",[64,2074,2075],{"id":2071},"Linting formulas before the workbook is saved",[68,2077,2078],{"id":2072},"Four steps. Find every cell whose value starts with an equals sign. Strip quoted text so literals are ignored. Extract function names and check each against openpyxl FORMULAE. Prefix known newer functions and report unknown names, failing the job if any remain.",[72,2080],{"x":74,"y":75,"width":76,"height":2081,"fill":78},"160",[72,2083],{"x":81,"y":82,"width":2084,"height":2085,"rx":2086,"fill":1020,"stroke":989,"style":88},"153.0","128.0","12",[90,2088,2090],{"transform":2089},"translate(84.5,46.5) scale(1.000)",[94,2091],{"d":2092,"fill":97,"stroke":2093,"style":2094},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[19,2096,2100],{"x":2097,"y":2098,"style":2099},"96.5","93.0","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Find formula cells",[19,2102,2104],{"x":2097,"y":2103,"style":1031},"112.5","value starts with \"=\"",[107,2106],{"x1":2107,"y1":2108,"x2":2109,"y2":2108,"stroke":995,"style":88},"178.0","80.0","200.0",[2111,2112],"polygon",{"points":2113,"fill":2114},"204.0,80.0 195.0,85.0 195.0,75.0","#5b5cf0",[72,2116],{"x":2117,"y":82,"width":2084,"height":2085,"rx":2086,"fill":1020,"stroke":989,"style":88},"209.0",[90,2119,2121],{"transform":2120},"translate(273.5,37.8) scale(1.000)",[94,2122],{"d":2123,"fill":97,"stroke":2093,"style":2094},"M3 5h18l-7 8v6l-4 2v-8z",[19,2125,2128],{"x":2126,"y":2127,"style":2099},"285.5","84.2","Strip string literals",[19,2130,2132],{"x":2126,"y":2131,"style":1031},"103.8","text in quotes is",[19,2134,2136],{"x":2126,"y":2135,"style":1031},"121.2","ignored",[107,2138],{"x1":2139,"y1":2108,"x2":147,"y2":2108,"stroke":995,"style":88},"367.0",[2111,2141],{"points":2142,"fill":2114},"393.0,80.0 384.0,85.0 384.0,75.0",[72,2144],{"x":2145,"y":82,"width":2084,"height":2085,"rx":2086,"fill":994,"stroke":995,"style":88},"398.0",[90,2147,2149],{"transform":2148},"translate(462.5,37.8) scale(1.000)",[94,2150],{"d":155,"fill":97,"stroke":2151,"style":2094},"var(--brand-strong,#4338ca)",[19,2153,2156],{"x":2154,"y":2127,"style":2155},"474.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Check each",[19,2158,2160],{"x":2154,"y":2159,"style":2155},"101.8","function",[19,2162,2163],{"x":2154,"y":2135,"style":1031},"in FORMULAE → fine",[107,2165],{"x1":2166,"y1":2108,"x2":2167,"y2":2108,"stroke":995,"style":88},"556.0","578.0",[2111,2169],{"points":2170,"fill":2114},"582.0,80.0 573.0,85.0 573.0,75.0",[72,2172],{"x":2173,"y":82,"width":2084,"height":2085,"rx":2086,"fill":2174,"stroke":144,"style":88},"587.0","#fdefd8",[90,2176,2178],{"transform":2177},"translate(651.5,29.0) scale(1.000)",[94,2179],{"d":143,"fill":97,"stroke":2180,"style":2094},"var(--gold-ink,#7a4e06)",[19,2182,2186],{"x":2183,"y":2184,"style":2185},"663.5","75.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Prefix or report",[19,2188,2190],{"x":2183,"y":2189,"style":1031},"95.0","known new ones get",[19,2192,2193],{"x":2183,"y":2103,"style":1031},"_xlfn.; the rest fail the",[19,2195,2197],{"x":2183,"y":2196,"style":1031},"130.0","job",[192,2199,2201],{"id":2200},"common-pitfalls","Common pitfalls",[2203,2204,2205,2215,2221,2227,2237],"ul",{},[2206,2207,2208,1384,2211,2214],"li",{},[1131,2209,2210],{},"Adding the prefix twice.",[22,2212,2213],{},"_xlfn._xlfn.XLOOKUP"," is as broken as no prefix. The linter's lookbehind skips names already preceded by a dot.",[2206,2216,2217,2220],{},[1131,2218,2219],{},"Assuming LibreOffice-tested files are fine in Excel, or the reverse."," Both apply the prefix rule, but check workbooks in the application your readers use.",[2206,2222,2223,2226],{},[1131,2224,2225],{},"Checking only the numbers your Python code expects."," A test that compares a DataFrame against expected totals proves the logic, not the formulas stored in the workbook. Lint the stored formula text as well, because that is what the spreadsheet will parse.",[2206,2228,2229,2232,2233,2236],{},[1131,2230,2231],{},"Building formulas from user data without quoting."," A customer called ",[22,2234,2235],{},"Smith & Co"," breaks an unquoted comparison in more ways than one.",[2206,2238,2239,2242,2243,2246,2247,2251],{},[1131,2240,2241],{},"Reading formulas back and expecting values."," openpyxl returns formula text, prefix included; for results, open with ",[22,2244,2245],{},"data_only=True"," after the file has been calculated. ",[47,2248,2250],{"href":2249},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002F","Read Formula Results with openpyxl data_only"," explains when cached values exist.",[192,2253,2255],{"id":2254},"performance-notes","Performance notes",[10,2257,2258,2259,2262],{},"The linter visits every cell once and runs one regular expression per formula, which takes well under a second for tens of thousands of formulas. On very large sheets, iterate with ",[22,2260,2261],{},"values_only=False"," only over the columns that hold formulas, or run the linter in tests against a representative output file rather than on every production run.",[192,2264,2266],{"id":2265},"conclusion","Conclusion",[10,2268,2269,2271,2272,2274,2275,2277,2278,2280],{},[22,2270,29],{}," in a formula written from Python usually means a newer function was stored without its ",[22,2273,37],{}," prefix — add it yourself with openpyxl, or let xlsxwriter's ",[22,2276,708],{}," do it. When the function is old or already prefixed, look for an undefined name, unquoted text, a localised function name or a typo. A short linter built on ",[22,2279,585],{}," catches all of them before the workbook leaves the job.",[192,2282,2284],{"id":2283},"frequently-asked-questions","Frequently asked questions",[10,2286,2287,2290],{},[1131,2288,2289],{},"Why does the formula work if I click into the cell and press Enter?","\nRe-entering the cell makes the spreadsheet parse the formula text itself, and it stores the function correctly. The file your script wrote stored the name without the _xlfn. prefix, so it was not recognised until the cell was re-entered.",[10,2292,2293,2296],{},[1131,2294,2295],{},"Which functions need the _xlfn. prefix?","\nFunctions added after the original .xlsx specification — XLOOKUP, XMATCH, TEXTJOIN, CONCAT, IFS, SWITCH, MAXIFS, MINIFS, IFNA, STDEV.S, VAR.S, the dynamic array functions and many statistical .DIST functions. A function missing from openpyxl.utils.FORMULAE is a candidate.",[10,2298,2299,2302],{},[1131,2300,2301],{},"Why do FILTER and SORT need _xlfn._xlws. instead?","\nThey are stored with an extra _xlws. part in the file format. Writing _xlfn.FILTER without it is still unrecognised. xlsxwriter's use_future_functions option applies the right form automatically.",[10,2304,2305,2308],{},[1131,2306,2307],{},"Can I write formulas in my local language, like SUMA or SOMME?","\nNo. The file always stores English function names with commas between arguments. Excel translates them for display in each user's language, so write =SUM(A1,A2) and a Spanish user will see =SUMA(A1;A2).",[192,2310,2312],{"id":2311},"related","Related",[2203,2314,2315,2321,2328,2335],{},[2206,2316,2317,2318,2320],{},"Up one level: ",[47,2319,50],{"href":49}," — other errors in generated workbooks.",[2206,2322,2323,2327],{},[47,2324,2326],{"href":2325},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formula-to-excel-cell-with-openpyxl\u002F","Write a Formula to an Excel Cell with openpyxl"," — the basics of writing formulas.",[2206,2329,2330,2334],{},[47,2331,2333],{"href":2332},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Ffind-formula-errors-in-a-workbook-with-python\u002F","Find #REF!, #DIV\u002F0! and Other Formula Errors in a Workbook"," — locating error values after calculation.",[2206,2336,2337,2341],{},[47,2338,2340],{"href":2339},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frecalculate-excel-formulas-without-excel-in-python\u002F","Recalculate Excel Formulas Without Excel in Python"," — checking results on a server.",[2343,2344,2345],"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 .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}html pre.shiki code .s_b0D, html code.shiki .s_b0D{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold}",{"title":20,"searchDepth":240,"depth":240,"links":2347},[2348,2349,2350,2351,2352,2353,2354,2355,2356,2357],{"id":194,"depth":240,"text":195},{"id":281,"depth":240,"text":282},{"id":701,"depth":240,"text":702},{"id":965,"depth":240,"text":966},{"id":1403,"depth":240,"text":1404},{"id":2200,"depth":240,"text":2201},{"id":2254,"depth":240,"text":2255},{"id":2265,"depth":240,"text":2266},{"id":2283,"depth":240,"text":2284},{"id":2311,"depth":240,"text":2312},"2026-09-25","Formulas that work when typed into Excel show #NAME? when openpyxl writes them. Newer functions must be stored with an _xlfn. prefix, and misspelled or localised names, missing defined names and unquoted text cause the same error. Lint every formula before saving.","md",[2362,2364,2366,2368],{"q":2289,"a":2363},"Re-entering the cell makes the spreadsheet parse the formula text itself, and it stores the function correctly. The file your script wrote stored the name without the _xlfn. prefix, so it was not recognised until the cell was re-entered.",{"q":2295,"a":2365},"Functions added after the original .xlsx specification — XLOOKUP, XMATCH, TEXTJOIN, CONCAT, IFS, SWITCH, MAXIFS, MINIFS, IFNA, STDEV.S, VAR.S, the dynamic array functions and many statistical .DIST functions. A function missing from openpyxl.utils.FORMULAE is a candidate.",{"q":2301,"a":2367},"They are stored with an extra _xlws. part in the file format. Writing _xlfn.FILTER without it is still unrecognised. xlsxwriter's use_future_functions option applies the right form automatically.",{"q":2307,"a":2369},"No. The file always stores English function names with commas between arguments. Excel translates them for display in each user's language, so write =SUM(A1,A2) and a Spanish user will see =SUMA(A1;A2).","fix name error for new excel functions written by python",null,{"breadcrumb":2373},[2374,2377,2380],{"name":2375,"item":2376},"Home","\u002F",{"name":2378,"item":2379},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":50,"item":49},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-name-error-for-new-excel-functions-written-by-python",{"title":2383,"description":2384},"Fix #NAME? Errors in openpyxl Formulas: the _xlfn. Prefix and Other Causes","Why XLOOKUP, TEXTJOIN, IFS, STDEV.S and CONCAT show #NAME? when written with openpyxl, how the _xlfn. prefix fixes them, and a formula linter that catches typos, localised names and missing defined names.","fix-name-error-for-new-excel-functions-written-by-python","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-name-error-for-new-excel-functions-written-by-python\u002Findex",[2388,2389,2390],"troubleshooting","excel-formulas","openpyxl","how-to","1lyS0mM5MEk5q-DRpwbBuRYP_1d9ZFMaG7SivEeAk5g",[2394,2398],{"title":2395,"path":2396,"stem":2397,"children":-1},"Fix \"Missing optional dependency 'openpyxl'\" in pandas","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-missing-optional-dependency-openpyxl","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-missing-optional-dependency-openpyxl\u002Findex",{"title":2399,"path":2400,"stem":2401,"children":-1},"Fix NoneType Errors When Reading Cells with openpyxl","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-nonetype-errors-when-reading-cells-with-openpyxl","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-nonetype-errors-when-reading-cells-with-openpyxl\u002Findex",[2403,2405],{"path":2404,"title":2378},"\u002Fgetting-started-with-python-excel-automation",{"path":2406,"title":50},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors",[],[2409,2412,2415,2418,2421,2424],{"path":2410,"title":2411,"kind":2036},"\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",{"path":2413,"title":2414,"kind":2391},"\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":2416,"title":2417,"kind":2036},"\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":2419,"title":2420,"kind":2391},"\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":2422,"title":2423,"kind":2391},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002Fhandle-microsoft-graph-throttling-for-excel","Handle Microsoft Graph Throttling in Excel Automation",{"path":2425,"title":2426,"kind":2427},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation","Error Handling and Logging in Excel Automation","guide",1790972065996]