← All guides

Your function exists, but your file cannot say so

Every compatibility question about a spreadsheet function has two halves, and almost everyone only asks the first. Does the engine implement this function? is the famous one. Can the file format name it? is the one that actually decides whether your workbook opens.

The OOXML spreadsheet format was frozen at the Excel 2007 function set. Everything added since — and that is now most of the interesting library — is stored in a .xlsx not under its own name but under a prefixed token: _xlfn.XLOOKUP, _xlfn._xlws.FILTER, _xlfn.T.INV.2T. Excel adds the prefix when it saves and strips it when it displays, so you never see it. Every other engine has to recognise the token, and where it does not, you get #NAME? for a function that engine can compute perfectly well.

The surprise

LibreOffice’s transport layer is lossy for LibreOffice itself, in three separate ways. It cannot read the token Excel writes for eight complex-number functions it fully implements. Its own .xlsx exporter silently collapses eleven of its own legacy function names onto other functions’ tokens, so those names cannot survive a save at all. And the token it writes for eight more of its own functions changed between 24.2 and 24.8, which means a file saved by LibreOffice 24.8 or later opens in LibreOffice 24.2 as #NAME? — a forward incompatibility inside one application’s own file format.

How we know, and what “probed” means here

This guide is unusual for this site in that its evidence is not only the executed corpus but the measurements that had to be made before the corpus could run. To execute a function honestly you must first write it into a workbook under a token the engine will read; get that wrong and you publish “unsupported” for a function that works. So every entry in harness/xlfn_map.py was measured in both directions on all four pinned builds (24.2.0.3, 24.8.7.2, 25.2.0.3, 25.8.7.3): import, by writing each candidate spelling into a workbook with openpyxl (which caches no value, so the engine must evaluate from scratch) and round-tripping it through soffice --headless --convert-to xlsx; and export, by feeding the same formulas to each build’s own parser and reading the stored token straight out of the raw sheet XML. Up to nine spellings were tried per function — plain, _xlfn., COM.MICROSOFT., ORG.OPENOFFICE., _xlfn.ORG.OPENOFFICE., ORG.LIBREOFFICE., _xlfn.ORG.LIBREOFFICE., _xlfn.COM.MICROSOFT. and COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.

The map now holds 165 prefixed storage tokens. 164 of them have executed test cases, and of those 137 evaluate in LibreOffice Calc 25.8.7.3 under the prefixed token — that is, the prefix is doing exactly its job and the function works. The other 27 return #NAME?, and the interesting question is which of those 27 are missing functions and which are missing mappings.

1. Eight functions LibreOffice has and cannot be told about

Microsoft’s XLSX-extensions future-function list gives the storage token for the Excel 2013 complex-number additions as _xlfn.IMCOSH, _xlfn.IMCOT, _xlfn.IMCSC, _xlfn.IMCSCH, _xlfn.IMSEC, _xlfn.IMSECH, _xlfn.IMSINH and _xlfn.IMTAN. That is what real Excel writes, so that is what our harness writes.

Formula (as typed)Excel (documented)Google Sheets (executed 2026-08-31)LibreOffice Calc 25.8.7.3 (executed, _xlfn. token)
=IMCOT("4+3i")0.00490118239430447-0.999266927805902i0.00490118239430447-0.999266927805902i#NAME?
=IMSEC("4+3i")-0.065294027857947-0.0752249603027732i-0.065294027857947-0.0752249603027732i#NAME?
=IMTAN("4+3i")0.00490825806749606+1.00070953606723i0.00490825806749606+1.00070953606723i#NAME?
=IMSINH("4+3i")-27.0168132580039+3.85373803791938i-27.0168132580039+3.85373803791938i#NAME?
=IMCOSH("4+3i")-27.0349456030742+3.85115333481178i-27.0349456030742+3.85115333481178i#NAME?
=IMCSC("4+3i")-0.0754898329158637+0.0648774713706355i-0.0754898329158637+0.0648774713706355i#NAME?
=IMCSCH("4+3i")-0.036275889628626-0.0051744731840194i-0.036275889628626-0.0051744731840194i#NAME?
=IMSECH("4+3i")-0.0362534969158689-0.00516434460775318i-0.0362534969158689-0.00516434460775318i#NAME?

All 24 cases across the eight functions returned #NAME? on all four builds. That looks like eight unsupported functions, and it is not. The five-spelling probe recorded in each test file settles it: _xlfn.IMCOT, COM.MICROSOFT.IMCOT, ORG.OPENOFFICE.IMCOT and _xlfn.ORG.OPENOFFICE.IMCOT are all #NAME? on every build, while the unprefixed IMCOT(…) evaluates on every build and returns exactly the documented string, byte for byte. LibreOffice implements all eight correctly. Its OOXML import simply has no mapping for the token Excel writes.

So the practical statement is the uncomfortable one: an Excel workbook that uses IMCOT arrives in LibreOffice as #NAME?, even though LibreOffice could compute IMCOT. Retyping the formula in LibreOffice makes it work. Saving that file back to .xlsx and reopening it does not.

2. The same mechanism, running the other way, for their real-number cousins

COT, COTH, CSC and CSCH are the direct trigonometric siblings of the functions above, added to Excel in the same release. For them the mapping exists and it is the only spelling that works:

Formula (as typed)Excel (documented)Google Sheets (executed 2026-08-31)LibreOffice Calc 25.8.7.3 (executed, _xlfn. token)
=ROUND(COT(30),9)-0.156119952-0.156119952-0.156119952
=ROUND(CSC(15),9)1.5377805621.5377805621.537780562
=ROUND(SEC(45),5)1.903591.903591.90359
=ROUND(T.INV.2T(0.05,10),9)2.2281388522.2281388522.228138852

Written under the bare name, all four of those are #NAME? in LibreOffice; written under _xlfn., they compute. The map records more than twenty such cases — the four trigonometric ones, SEC, SECH, SKEW.P, the six-strong T.DIST/T.INV family, T.TEST, WEIBULL.DIST, Z.TEST, MUNIT, NEGBINOM.DIST, PHI and POISSON.DIST. Each of them would have been published as “unsupported in LibreOffice” by a harness that wrote the plain name, and each of them works.

BAHTTEXT is the odd one in this group and worth knowing about because no vendor table predicts it: it predates 2007 and is absent from the public future-function list, but LibreOffice’s own OOXML function table tags it as stored-as-macro-call, and empirically =_xlfn.BAHTTEXT(1234) returns the exact Thai string Microsoft documents on all four builds while =BAHTTEXT(1234) is #NAME? on all four.

ISO.CEILING goes the other way and is the reason this map is measured rather than copied. It is a post-2007 function, but Microsoft’s own storage list spells exactly four future functions without the prefix — ECMA.CEILING, ISO.CEILING, NETWORKDAYS.INTL and WORKDAY.INTL — while its 155 neighbours carry _xlfn.. LibreOffice’s own filter draws the same line. Empirically, on all four builds =ISO.CEILING(4.3) returns 5 while =_xlfn.ISO.CEILING(4.3) and =COM.MICROSOFT.ISO.CEILING(4.3) are #NAME?, and round-tripping through LibreOffice’s own export writes the bare token back. An earlier version of our map had this entry wrong, which would have published a false “unsupported” verdict; the export measurement is what caught it.

3. Eleven LibreOffice names its own exporter erases

LibreOffice keeps a set of legacy aliases — the Analysis-ToolPak-era _ADD forms, the _EXCEL2003 forms, and two others. They exist, they compute, and they have no reachable OOXML token at all, because LibreOffice’s own .xlsx export collapses each of them onto another function’s name:

LibreOffice nameToken LibreOffice writes on exportResult of every import spelling probed
CUMIPMT_ADDCUMIPMT#NAME? on all four builds
CUMPRINC_ADDCUMPRINC#NAME? on all four builds
EFFECT_ADDEFFECT#NAME? on all four builds
NOMINAL_ADDNOMINAL#NAME? on all four builds
GCD_EXCEL2003GCD#NAME? on all four builds
LCM_EXCEL2003LCM#NAME? on all four builds
ISEVEN_ADDISEVEN#NAME? on all four builds
ISODD_ADDISODD#NAME? on all four builds
WEEKNUM_EXCEL2003WEEKNUM#NAME? on all four builds
FORMULA_xlfn.FORMULATEXT#NAME? on all four builds
SKEWP_xlfn.SKEW.P#NAME? on all four builds

Nine spellings were probed for each; all nine are #NAME? on all four builds, and the export direction explains why. Save a .xlsx from LibreOffice and the alias is simply gone, replaced by its modern namesake. For most of the eleven that substitution is harmless — ISEVEN_ADD and ISEVEN do the same thing — but it is worth knowing that the name in your formula bar is not the name in your file, and that a formula audit tool reading the XML will see the modern function, not the one you wrote.

This is also why you will not find these eleven in our function corpus with a verdict attached. There is deliberately no test file for any of them: writing CUMIPMT into a workbook tests CUMIPMT, not CUMIPMT_ADD, and a #NAME? run would have published “unsupported in LibreOffice” for eleven functions LibreOffice genuinely implements. They appear on our coverage list as documented skips, with the reason, rather than as a verdict we are not entitled to.

4. A LibreOffice file that LibreOffice cannot open

This is the finding that only running four builds could produce. Eight LibreOffice-only functions — DAYSINMONTH, DAYSINYEAR, ISLEAPYEAR, MONTHS, ROT13, WEEKS, WEEKSINYEAR and YEARS — changed their OOXML export token between 24.2 and 24.8:

BuildToken it writes on exportTokens it accepts on import
LibreOffice 24.2.0.3ORG.OPENOFFICE.ROT13ORG.OPENOFFICE.ROT13 only — the bare name is #NAME?
LibreOffice 24.8.7.2ROT13both
LibreOffice 25.2.0.3ROT13both
LibreOffice 25.8.7.3ROT13both

Read that table in the direction that hurts. A colleague on 24.8, 25.2 or 25.8 saves an .xlsx containing =ISLEAPYEAR(A1). The file writes the bare token. You open it on 24.2 — still shipping in long-support distributions — and the formula is #NAME?, in the same application, for a function both builds implement. (A curiosity from the same probe: on 24.2 the bare =ROT13(...) comes back #VALUE! rather than #NAME?, so even the error does not tell you what happened.) Our map records the ORG.OPENOFFICE. form precisely because it is the one all four builds read; using the bare name would have produced eight false “unsupported in LibreOffice 24.2” verdicts.

All eight functions themselves are fine. Executed on 2026-09-01 under the token all four builds accept, they return the documented values on every build — =ROT13("Gur Qbphzrag Sbhaqngvba jnf sbhaqrq va Frcgrzore 2010.") gives back “The Document Foundation was founded in September 2010.”, =ISLEAPYEAR(DATE(1968,2,29)) gives 1 and =ISLEAPYEAR(DATE(2100,1,1)) gives 0. Google Sheets has none of the eight; all of their cases are #NAME? there, which is an honest unsupported verdict rather than a transport problem.

The namespace rule underneath all this is vintage: functions inherited from OpenOffice.org take ORG.OPENOFFICE., functions LibreOffice added after the fork take ORG.LIBREOFFICE.. It is not applied consistently. EASTERSUNDAY and ERRORTYPE are OpenOffice.org-era yet carry _xlfn. on top of ORG.OPENOFFICE. on all four builds, where their eight neighbours above do not. CONVERT_OOO is not prefixed but renamed, to _xlfn.ORG.OPENOFFICE.CONVERT — no prefix rule can express a rename, which is why our map stores whole tokens. RAND.NV and RANDBETWEEN.NV are reachable under exactly one of nine spellings each, and the bare name is not it. CURRENT answers to both the bare name and the prefixed one but is always written back prefixed. DDE answers only to the bare name and is written back bare.

5. Google’s importer has the same class of gap

This is not a LibreOffice-only phenomenon, and it is worth saying so plainly. Our first Google Sheets run wrote the same Excel-authored workbooks, prefixes and all, and Google’s importer maps some prefixes but not others: _xlfn.XLOOKUP, _xlfn.MAP and _xlfn.LAMBDA evaluated fine with the prefix, while _xlfn._xlws.FILTER and _xlfn._xlws.SORT came back #NAME? and BYROW, BYCOL and MAKEARRAY came back #ERROR! — for five functions Google documents and implements. We published those as inconclusive rather than unsupported, then re-ran the same corpus with plain, unprefixed names on 2026-08-29, which resolved all five into real executed verdicts. The two runs are merged into one results file with per-function provenance for which run produced which verdict. The general caveat stands for anything we have not re-run that way, and it is written up in the Google Sheets execution caveats.

What to do about it

Diagnose #NAME? by retyping, not by searching. If a formula shows #NAME? after opening a file, delete the cell contents and type the same formula in by hand. If it now computes, you have a storage-token problem, not a missing function, and the fix is a file-level one. If it still fails, the function really is absent in that engine.

Do not write raw OOXML with plain modern function names. This bites hardest outside the office suites entirely: openpyxl, XlsxWriter and every other library that writes sheet XML directly will happily store =XLOOKUP(...) verbatim, and then both Excel and LibreOffice show #NAME? for a function both support. That is the single most common false “compatibility bug” in generated spreadsheets, and it is a serialization bug in the generator.

Treat a version floor as a file-format question, not just a feature question. The 24.2/24.8 split above means “everyone is on LibreOffice” is not sufficient for a shared workbook. If any of those eight functions is in the file, everyone needs to be on 24.8 or later, or the file needs to avoid them.

Prefer the portable spelling when one exists. Where a LibreOffice-only alias has a modern namesake — and for nine of the eleven in section 3 it does — using the modern name costs nothing and survives every round trip, because it is what the file was going to say anyway.

Honest limits

The Excel column throughout is Microsoft’s documented behaviour and Microsoft’s published storage-token list, as recorded in our test corpus. We do not run Excel, and no value in that column is a measurement — including the claim that Excel writes a given token, which comes from the published extensions list rather than from a file we saved from Excel.

The Google Sheets column is executed output from dated runs, because Sheets has no version number to pin: a formula-only .xlsx carrying no cached results goes to Google Drive, is recalculated by Google’s engine, and comes back as .xlsx for readback, with a deterministic =1111+2222 canary in every sheet proving the recalculation happened. The complex-number and trigonometric cases in sections 1 and 2 ran on 2026-08-31; the LibreOffice-only functions in section 4 ran on 2026-09-01; the prefix-mapping observations in section 5 date from the 2026-08-29 runs.

The LibreOffice column is executed output from Calc 25.8.7.3 unless a row names another build, and every corpus case cited here returned identical results on 24.2.0.3, 24.8.7.2 and 25.2.0.3 — except, by construction, the 24.2 import behaviour in section 4, which is the finding. Those four builds are the only ones we tested, so “the token changed between 24.2 and 24.8” means exactly that and not that we have bisected which release made the change.

The spelling probes throughout — the five-spelling and nine-spelling sweeps, the export-token readings out of raw sheet XML, and the eleven collapsed aliases — are measurements recorded in harness/xlfn_map.py rather than rows in the published corpus. They are reproducible the same way and by the same commands, but they are not test cases with verdicts, and the eleven aliases deliberately have no verdict at all.

Scope. This guide covers the tokens our corpus needed, which is 165 prefixed names plus 17 LibreOffice-only ones. Untested here: every OOXML function name we had no reason to write, defined names and LAMBDA parameters (which use a third prefix, _xlpm.), the legacy .xls binary format, ODF as a transport, and what Excel itself does when it opens a file LibreOffice wrote. See our methodology for how recalculation is proven rather than assumed, and the function pages for IMCOT, COT, ISO.CEILING and ROT13 for the per-engine support matrices.

Check before you migrate