Search before asking
Fesod version
main @ c8224b8 (2.1.0-SNAPSHOT)
JDK version
OpenJDK 21.0.5 (Temurin)
Operating system
macOS 15
Steps To Reproduce
A cell can hold a literal error value — an error stored as the cell value itself rather than as a formula result. Excel produces these with "Paste Special → Values" over a formula error, and by typing #N/A directly into a cell.
Write the same row to both formats with POI and read both back with Fesod:
// same content written to both .xls (HSSFWorkbook) and .xlsx (XSSFWorkbook)
Row row = workbook.createSheet("sheet").createRow(0);
row.createCell(0).setCellValue(true);
row.createCell(1).setCellErrorValue(FormulaError.DIV0.getCode());
row.createCell(2).setCellErrorValue(FormulaError.NA.getCode());
row.createCell(3).setCellErrorValue(FormulaError.NULL.getCode());
row.createCell(4).setCellValue("marker");
List<Map<Integer, Object>> rows =
FesodSheet.read(file).headRowNumber(0).sheet(0).doReadSync();
Current Behavior
xls row0 = {0=true, 1=true, 2=true, 3=false, 4=marker}
xlsx row0 = {0=true, 1=#DIV/0!, 2=#N/A, 3=#NULL!, 4=marker}
The three error cells come back from .xls as booleans. Note that they do not even agree with each other: #DIV/0! and #N/A become true while #NULL! becomes false.
Apache POI's own usermodel reads all three as CellType.ERROR from both files, so the data is written correctly and only the read path differs.
The result is a silent data error: an error marker becomes a plausible-looking boolean, both the "this is an error" fact and the specific error type are lost, and the same workbook content yields different values depending on whether it was saved as .xls or .xlsx.
Expected Behavior
.xls should return the error text, the same as .xlsx already does:
xls row0 = {0=true, 1=#DIV/0!, 2=#N/A, 3=#NULL!, 4=marker}
Anything else?
Root cause. BoolErrRecordHandler#processRecord calls ber.getBooleanValue() unconditionally:
https://github.com/apache/fesod/blob/c8224b8/fesod-sheet/src/main/java/org/apache/fesod/sheet/analysis/v03/handlers/BoolErrRecordHandler.java#L55-L59
A BIFF BOOLERR record stores either a boolean or an error code, distinguished by its fError flag (POI exposes this as isBoolean() / isError()). For an error record POI's getBooleanValue() returns errorCode != 0, which is why #DIV/0! (code 7) and #N/A (code 42) turn into true and #NULL! (code 0) turns into false.
The handler therefore only implements the boolean half of the record type. This is inconsistent with three places in Fesod itself:
- the XLSX read path —
CellTagHandler maps t="e" cells to the error text;
- the XLS formula read path —
FormulaRecordHandler maps a formula whose cached result is an error to CellDataTypeEnum.ERROR;
StringErrorConverter, which exists specifically to convert ERROR cells to their text.
I'm happy to open a PR: branch on isError() and produce an ERROR cell carrying the error text, so the existing StringErrorConverter path yields the same user-visible value as XLSX.
This report was produced with AI assistance; I reproduced the behaviour locally and reviewed every conclusion myself.
Are you willing to submit a PR?
Search before asking
Fesod version
main @ c8224b8 (2.1.0-SNAPSHOT)
JDK version
OpenJDK 21.0.5 (Temurin)
Operating system
macOS 15
Steps To Reproduce
A cell can hold a literal error value — an error stored as the cell value itself rather than as a formula result. Excel produces these with "Paste Special → Values" over a formula error, and by typing
#N/Adirectly into a cell.Write the same row to both formats with POI and read both back with Fesod:
Current Behavior
The three error cells come back from
.xlsas booleans. Note that they do not even agree with each other:#DIV/0!and#N/Abecometruewhile#NULL!becomesfalse.Apache POI's own usermodel reads all three as
CellType.ERRORfrom both files, so the data is written correctly and only the read path differs.The result is a silent data error: an error marker becomes a plausible-looking boolean, both the "this is an error" fact and the specific error type are lost, and the same workbook content yields different values depending on whether it was saved as
.xlsor.xlsx.Expected Behavior
.xlsshould return the error text, the same as.xlsxalready does:Anything else?
Root cause.
BoolErrRecordHandler#processRecordcallsber.getBooleanValue()unconditionally:https://github.com/apache/fesod/blob/c8224b8/fesod-sheet/src/main/java/org/apache/fesod/sheet/analysis/v03/handlers/BoolErrRecordHandler.java#L55-L59
A BIFF
BOOLERRrecord stores either a boolean or an error code, distinguished by itsfErrorflag (POI exposes this asisBoolean()/isError()). For an error record POI'sgetBooleanValue()returnserrorCode != 0, which is why#DIV/0!(code 7) and#N/A(code 42) turn intotrueand#NULL!(code 0) turns intofalse.The handler therefore only implements the boolean half of the record type. This is inconsistent with three places in Fesod itself:
CellTagHandlermapst="e"cells to the error text;FormulaRecordHandlermaps a formula whose cached result is an error toCellDataTypeEnum.ERROR;StringErrorConverter, which exists specifically to convertERRORcells to their text.I'm happy to open a PR: branch on
isError()and produce anERRORcell carrying the error text, so the existingStringErrorConverterpath yields the same user-visible value as XLSX.This report was produced with AI assistance; I reproduced the behaviour locally and reviewed every conclusion myself.
Are you willing to submit a PR?