← All guides

CHAR(0) makes an invisible character in LibreOffice instead of an error

Microsoft documents CHAR as taking “a number between 1 and 255”, and UNICHAR's reference page is explicit that a number of zero or less returns the #VALUE! error. LibreOffice Calc does not reject zero. It builds the character for code point 0 — the NUL control character — and hands it back as an ordinary string. When our harness read the recalculated workbook, that cell came back as the literal seven-character text _x0000_, which is the escape the .xlsx format uses to store a NUL inside a string.

The surprise

This is the silent kind of divergence. Excel stops with a visible error; LibreOffice returns a string that has content but no appearance. On screen the cell looks empty. LEN of it is not zero, an = comparison with "" is false, and exporting the sheet writes a real NUL byte into your CSV — the kind of thing that makes a downstream database import fail with an error that names a file, not a formula.

Executed results

FormulaExcel, desktop (documented)Google Sheets (executed 2026-08-29)LibreOffice Calc 25.8.7.3 (executed)
=CHAR(0)#VALUE!#NUM!_x0000_
=UNICHAR(0)#VALUE!#VALUE!_x0000_
=CHAR(256)#VALUE!ฤ€#VALUE!
=UNICHAR(-1)#VALUE!#VALUE!#VALUE!
=CHAR(65)AAA
=UNICHAR(233)éรฉé
=UNICHAR(128512)😀๐Ÿ˜€😀
=CODE(CHAR(97))979797

The Excel column is the documented-expected value from our test corpus; we did not run desktop Excel. The LibreOffice column is what our harness read back after recalculating the workbook in LibreOffice Calc 25.8.7.3. Read the table as a whole and the shape of the bug is clear: LibreOffice does range-check these functions — =CHAR(256) and =UNICHAR(-1) both return #VALUE!, matching Excel — and it handles ordinary code points, accents and even supplementary-plane emoji identically. Zero is the single value that slips through the check.

Excel for the web is a separate application from the desktop product, and that one we do execute. Recalculated on OneDrive on 2026-09-01 it returned #VALUE! for =CHAR(0), =UNICHAR(0) and =CHAR(256) — the documented values in all three, and in the first two not what LibreOffice returns. So the documented column here is now also a measured result in a Microsoft engine; it still says nothing about what the desktop product does.

A note on what _x0000_ means

_x0000_ is not a piece of text LibreOffice invented. It is the standard OOXML escape for a control character that cannot appear literally in the XML of an .xlsx file, so a cell whose value is a NUL character is written to disk as _x0000_ and that is what our harness read. The practical takeaway is the same either way: the formula produced a character, not an error. In the LibreOffice UI you would see an empty-looking cell; in a file handed to another program you get either a NUL byte or the literal escape text, and both are trouble.

Consistent across LibreOffice versions

=CHAR(0) and =UNICHAR(0) produced the same result in 24.2.0.3, 24.8.7.2, 25.2.0.3 and 25.8.7.3, and the two out-of-range rows returned #VALUE! in all four builds. Long-standing behaviour, not a recent change.

Why it happens

Excel's range check is inclusive of the documented lower bound: 1 is the smallest valid argument, so 0 is rejected. LibreOffice's check evidently starts below that, so 0 maps to U+0000 and is returned like any other character. The divergence only surfaces when the argument is computed rather than typed — =CHAR(A1) where A1 is empty, or =CHAR(CODE(x)-64) on an unexpected input, or a lookup that returns nothing. In Excel that mistake shows itself; in LibreOffice it disappears into a column of apparently blank cells.

How to migrate safely

Guard the argument rather than trusting the function to reject it: =IF(n<1,"",CHAR(n)) gives every engine the same answer and makes the intent explicit. Where you are cleaning up data that may already contain these characters, CLEAN is the tool for the job — it strips control characters, and our executed run confirms =CLEAN("Hello"&CHAR(7)&"World") returns HelloWorld in LibreOffice 25.8.7.3. We have not executed CLEAN against a NUL specifically, so verify that case in your own file before relying on it; =SUBSTITUTE(x,CHAR(0),"") is the direct alternative.

When auditing, look for the symptom rather than the formula: a text column where =LEN(cell) disagrees with what you can see, or a key column where lookups miss on rows that look identical, is the fingerprint of an invisible character. And if you have ever seen the literal string _x0000_ appear in an exported file, this class of formula is where it comes from.

Honest limits

The Excel column is Microsoft's documented behaviour recorded in our test corpus, not values we executed in Excel. The Google Sheets column is executed output from a Drive import on 2026-08-29, and Sheets does not simply follow Excel: =CHAR(0) returns #NUM! where Excel documents #VALUE!, and =CHAR(256) returns the character Ā instead of erroring at all. Only the two UNICHAR out-of-range rows match Excel’s documented #VALUE!. So all three engines answer CHAR(0) differently. The LibreOffice column is executed output from LibreOffice Calc 25.8.7.3, reproduced in our three earlier version runs; the exact rendering of the NUL character depends on how the reading program handles it, and _x0000_ is what our .xlsx reader reported.

Check before you migrate

A note on which Excel this is. The Excel column in the tables above is Microsoft’s documented behaviour for desktop Excel, as recorded in our test corpus — we do not run desktop Excel, and no value in that column is a measurement. Excel for the web is a different application with its own calculation engine, and that one we do run (recalculated on OneDrive, 2026-09-01). Its measured results are published on each function’s own page rather than in these guide tables. Because we have no desktop run to compare against, a disagreement between an Excel-web measurement and the documented column is genuinely ambiguous: it may mean the web engine diverges from the desktop one, or that the documentation is wrong about both. We do not claim to know which.